<!doctype html><html lang=zh class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel="shortcut icon" href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.1.2, mkdocs-material-5.5.13"><title>HDFS - Dayet</title><link rel=stylesheet href=../../assets/stylesheets/main.077507d7.min.css><link rel=stylesheet href=../../assets/stylesheets/palette.ff0a5ce4.min.css><meta name=theme-color content=#546d78><link href=https://fonts.gstatic.com rel=preconnect crossorigin><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700%7CConsolas&display=fallback"><style>body,input{font-family:"Roboto",-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Consolas",SFMono-Regular,Consolas,Menlo,monospace}</style><script>window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)},ga.l=+new Date,ga("create","UA-XXXXXXXX-X","auto"),ga("set","anonymizeIp",!0),ga("send","pageview"),document.addEventListener("DOMContentLoaded",function(){document.forms.search&&document.forms.search.query.addEventListener("blur",function(){if(this.value){var e=document.location.pathname;ga("send","pageview",e+"?q="+this.value)}})}),document.addEventListener("DOMContentSwitch",function(){ga("send","pageview",document.location.pathname)})</script><script async src=https://www.google-analytics.com/analytics.js></script></head> <body dir=ltr data-md-color-scheme data-md-color-primary=blue-grey data-md-color-accent=blue-grey> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#hadoop-hdfs class=md-skip> 跳转至 </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header-nav md-grid" aria-label=Header> <a href=../.. title=Dayet class="md-header-nav__button md-logo" aria-label=Dayet> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 003-3 3 3 0 00-3-3 3 3 0 00-3 3 3 3 0 003 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54z"/></svg> </a> <label class="md-header-nav__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg> </label> <div class=md-header-nav__title data-md-component=header-title> <div class=md-header-nav__ellipsis> <span class="md-header-nav__topic md-ellipsis"> Dayet </span> <span class="md-header-nav__topic md-ellipsis"> HDFS </span> </div> </div> <label class="md-header-nav__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0116 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 019.5 16 6.5 6.5 0 013 9.5 6.5 6.5 0 019.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg> </label> <div class=md-search data-md-component=search role=dialog> <label class=md-search__overlay for=__search></label> <div class=md-search__inner role=search> <form class=md-search__form name=search> <input type=text class=md-search__input name=query aria-label=搜索 placeholder=搜索 autocapitalize=off autocorrect=off autocomplete=off spellcheck=false data-md-component=search-query data-md-state=active> <label class="md-search__icon md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0116 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 019.5 16 6.5 6.5 0 013 9.5 6.5 6.5 0 019.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg> </label> <button type=reset class="md-search__icon md-icon" aria-label=Clear data-md-component=search-reset tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg> </button> </form> <div class=md-search__output> <div class=md-search__scrollwrap data-md-scrollfix> <div class=md-search-result data-md-component=search-result> <div class=md-search-result__meta> Initializing search </div> <ol class=md-search-result__list></ol> </div> </div> </div> </div> </div> <div class=md-header-nav__source> <a href=https://chokgit.gitee.io/blog title="前往 GitHub 仓库" class=md-source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 448 512"><path d="M439.55 236.05L244 40.45a28.87 28.87 0 00-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 01-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 000 40.81l195.61 195.6a28.86 28.86 0 0040.8 0l194.69-194.69a28.86 28.86 0 000-40.81z"/></svg> </div> <div class=md-source__repository> 吾生也有崖，而知也无涯。 </div> </a> </div> </nav> </header> <div class=md-container data-md-component=container> <main class=md-main data-md-component=main> <div class="md-main__inner md-grid"> <div class="md-sidebar md-sidebar--primary" data-md-component=navigation> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--primary" aria-label=Navigation data-md-level=0> <label class=md-nav__title for=__drawer> <a href=../.. title=Dayet class="md-nav__button md-logo" aria-label=Dayet> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 003-3 3 3 0 00-3-3 3 3 0 00-3 3 3 3 0 003 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54z"/></svg> </a> Dayet </label> <div class=md-nav__source> <a href=https://chokgit.gitee.io/blog title="前往 GitHub 仓库" class=md-source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 448 512"><path d="M439.55 236.05L244 40.45a28.87 28.87 0 00-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 01-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 000 40.81l195.61 195.6a28.86 28.86 0 0040.8 0l194.69-194.69a28.86 28.86 0 000-40.81z"/></svg> </div> <div class=md-source__repository> 吾生也有崖，而知也无涯。 </div> </a> </div> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../.. title=主页 class=md-nav__link> 主页 </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-2 type=checkbox id=nav-2> <label class=md-nav__link for=nav-2> 系统基础 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=系统基础 data-md-level=1> <label class=md-nav__title for=nav-2> <span class="md-nav__icon md-icon"></span> 系统基础 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E7%B3%BB%E7%BB%9F/Linux/ title=Linux class=md-nav__link> Linux </a> </li> <li class=md-nav__item> <a href=../../%E7%B3%BB%E7%BB%9F/Shell/ title=Shell class=md-nav__link> Shell </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-3 type=checkbox id=nav-3> <label class=md-nav__link for=nav-3> 编程语言 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=编程语言 data-md-level=1> <label class=md-nav__title for=nav-3> <span class="md-nav__icon md-icon"></span> 编程语言 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/JavaSE/ title=Java class=md-nav__link> Java </a> </li> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Scala/ title=Scala class=md-nav__link> Scala </a> </li> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Python/ title=Python class=md-nav__link> Python </a> </li> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Kotlin/ title=Kotlin class=md-nav__link> Kotlin </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-4 type=checkbox id=nav-4> <label class=md-nav__link for=nav-4> 前端技术 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=前端技术 data-md-level=1> <label class=md-nav__title for=nav-4> <span class="md-nav__icon md-icon"></span> 前端技术 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%89%8D%E7%AB%AF/Vue/ title=Vue class=md-nav__link> Vue </a> </li> <li class=md-nav__item> <a href=../../%E5%89%8D%E7%AB%AF/Element-UI/ title=Element-UI-admin class=md-nav__link> Element-UI-admin </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-5 type=checkbox id=nav-5> <label class=md-nav__link for=nav-5> 后端技术 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=后端技术 data-md-level=1> <label class=md-nav__title for=nav-5> <span class="md-nav__icon md-icon"></span> 后端技术 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%90%8E%E7%AB%AF/SpringBoot/ title=SpringBoot class=md-nav__link> SpringBoot </a> </li> <li class=md-nav__item> <a href=../../%E5%90%8E%E7%AB%AF/Mybatis/ title=Mybatis class=md-nav__link> Mybatis </a> </li> <li class=md-nav__item> <a href=../../%E5%90%8E%E7%AB%AF/SpringData/ title=SpringData class=md-nav__link> SpringData </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-6 type=checkbox id=nav-6> <label class=md-nav__link for=nav-6> 中间件 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=中间件 data-md-level=1> <label class=md-nav__title for=nav-6> <span class="md-nav__icon md-icon"></span> 中间件 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E4%B8%AD%E9%97%B4%E4%BB%B6/Nginx/ title=Nginx class=md-nav__link> Nginx </a> </li> <li class=md-nav__item> <a href=../../%E4%B8%AD%E9%97%B4%E4%BB%B6/Tomcat/ title=Tomcat class=md-nav__link> Tomcat </a> </li> <li class=md-nav__item> <a href=../../%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ/ title=RabbitMQ class=md-nav__link> RabbitMQ </a> </li> <li class=md-nav__item> <a href=../../%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ/ title=RocketMQ class=md-nav__link> RocketMQ </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--active md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-7 type=checkbox id=nav-7 checked> <label class=md-nav__link for=nav-7> 大数据 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=大数据 data-md-level=1> <label class=md-nav__title for=nav-7> <span class="md-nav__icon md-icon"></span> 大数据 </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--active md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-7-1 type=checkbox id=nav-7-1 checked> <label class=md-nav__link for=nav-7-1> Hadoop <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=Hadoop data-md-level=2> <label class=md-nav__title for=nav-7-1> <span class="md-nav__icon md-icon"></span> Hadoop </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../Hadoop%E5%9F%BA%E7%A1%80/ title=入门 class=md-nav__link> 入门 </a> </li> <li class="md-nav__item md-nav__item--active"> <input class="md-nav__toggle md-toggle" data-md-toggle=toc type=checkbox id=__toc> <label class="md-nav__link md-nav__link--active" for=__toc> HDFS <span class="md-nav__icon md-icon"></span> </label> <a href=./ title=HDFS class="md-nav__link md-nav__link--active"> HDFS </a> <nav class="md-nav md-nav--secondary" aria-label=目录> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> 目录 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=#1-hdfs class=md-nav__link> 第1章 HDFS概述 </a> </li> <li class=md-nav__item> <a href=#11-hdfs class=md-nav__link> 1.1 HDFS产出背景及定义 </a> </li> <li class=md-nav__item> <a href=#12-hdfs class=md-nav__link> 1.2 HDFS优缺点 </a> </li> <li class=md-nav__item> <a href=#13-hdfs class=md-nav__link> 1.3 HDFS组成架构 </a> </li> <li class=md-nav__item> <a href=#14-hdfs class=md-nav__link> 1.4 HDFS文件块大小 </a> </li> <li class=md-nav__item> <a href=#2-hdfsshell class=md-nav__link> 第2章 HDFS的Shell操作（开发重点） </a> </li> <li class=md-nav__item> <a href=#3-hdfs class=md-nav__link> 第3章 HDFS客户端操作（开发重点） </a> </li> <li class=md-nav__item> <a href=#31-hdfs class=md-nav__link> 3.1 HDFS客户端环境准备 </a> </li> <li class=md-nav__item> <a href=#32-hdfsapi class=md-nav__link> 3.2 HDFS的API操作 </a> <nav class=md-nav aria-label="3.2 HDFS的API操作"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#321-hdfs class=md-nav__link> 3.2.1 HDFS文件上传（测试参数优先级） </a> </li> <li class=md-nav__item> <a href=#322-hdfs class=md-nav__link> 3.2.2 HDFS文件下载 </a> </li> <li class=md-nav__item> <a href=#323-hdfs class=md-nav__link> 3.2.3 HDFS文件夹删除 </a> </li> <li class=md-nav__item> <a href=#324-hdfs class=md-nav__link> 3.2.4 HDFS文件名更改 </a> </li> <li class=md-nav__item> <a href=#325-hdfs class=md-nav__link> 3.2.5 HDFS文件详情查看 </a> </li> <li class=md-nav__item> <a href=#326-hdfs class=md-nav__link> 3.2.6 HDFS文件和文件夹判断 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#33-hdfsio class=md-nav__link> 3.3 HDFS的I/O流操作 </a> <nav class=md-nav aria-label="3.3 HDFS的I/O流操作"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#331-hdfs class=md-nav__link> 3.3.1 HDFS文件上传 </a> </li> <li class=md-nav__item> <a href=#332-hdfs class=md-nav__link> 3.3.2 HDFS文件下载 </a> </li> <li class=md-nav__item> <a href=#333 class=md-nav__link> 3.3.3 定位文件读取 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#4-hdfs class=md-nav__link> 第4章 HDFS的数据流 </a> </li> <li class=md-nav__item> <a href=#41-hdfs class=md-nav__link> 4.1 HDFS写数据流程 </a> <nav class=md-nav aria-label="4.1 HDFS写数据流程"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#411 class=md-nav__link> 4.1.1 剖析文件写入 </a> </li> <li class=md-nav__item> <a href=#412- class=md-nav__link> 4.1.2 网络拓扑-节点距离计算 </a> </li> <li class=md-nav__item> <a href=#413 class=md-nav__link> 4.1.3 机架感知（副本存储节点选择） </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#42-hdfs class=md-nav__link> 4.2 HDFS读数据流程 </a> </li> <li class=md-nav__item> <a href=#5-namenodesecondarynamenode class=md-nav__link> 第5章 NameNode和SecondaryNameNode（重点） </a> </li> <li class=md-nav__item> <a href=#51-nn2nn class=md-nav__link> 5.1 NN和2NN工作机制 </a> </li> <li class=md-nav__item> <a href=#52-fsimageedits class=md-nav__link> 5.2 Fsimage和Edits解析 </a> </li> <li class=md-nav__item> <a href=#53-checkpoint class=md-nav__link> 5.3 CheckPoint时间设置 </a> </li> <li class=md-nav__item> <a href=#54-namenode class=md-nav__link> 5.4 NameNode故障处理 </a> </li> <li class=md-nav__item> <a href=#55 class=md-nav__link> 5.5 集群安全模式 </a> </li> <li class=md-nav__item> <a href=#56-namenode class=md-nav__link> 5.6 NameNode多目录配置 </a> </li> <li class=md-nav__item> <a href=#6-datanode class=md-nav__link> 第6章 DataNode </a> </li> <li class=md-nav__item> <a href=#61-datanode class=md-nav__link> 6.1 DataNode工作机制 </a> </li> <li class=md-nav__item> <a href=#62 class=md-nav__link> 6.2 数据完整性 </a> </li> <li class=md-nav__item> <a href=#63 class=md-nav__link> 6.3 掉线时限参数设置 </a> </li> <li class=md-nav__item> <a href=#64 class=md-nav__link> 6.4 服役新数据节点 </a> </li> <li class=md-nav__item> <a href=#65 class=md-nav__link> 6.5 退役旧数据节点 </a> <nav class=md-nav aria-label="6.5 退役旧数据节点"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#651 class=md-nav__link> 6.5.1 添加白名单 </a> </li> <li class=md-nav__item> <a href=#652 class=md-nav__link> 6.5.2 黑名单退役 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#66-datanode class=md-nav__link> 6.6 Datanode多目录配置 </a> </li> <li class=md-nav__item> <a href=#7-hdfs-2x class=md-nav__link> 第7章 HDFS 2.X新特性 </a> </li> <li class=md-nav__item> <a href=#71 class=md-nav__link> 7.1 集群间数据拷贝 </a> </li> <li class=md-nav__item> <a href=#72 class=md-nav__link> 7.2 小文件存档 </a> </li> <li class=md-nav__item> <a href=#73 class=md-nav__link> 7.3 回收站 </a> </li> <li class=md-nav__item> <a href=#74 class=md-nav__link> 7.4 快照管理 </a> </li> <li class=md-nav__item> <a href=#8-hdfs-ha class=md-nav__link> 第8章 HDFS HA高可用 </a> </li> <li class=md-nav__item> <a href=#81-ha class=md-nav__link> 8.1 HA概述 </a> </li> <li class=md-nav__item> <a href=#82-hdfs-ha class=md-nav__link> 8.2 HDFS-HA工作机制 </a> <nav class=md-nav aria-label="8.2 HDFS-HA工作机制"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#821-hdfs-ha class=md-nav__link> 8.2.1 HDFS-HA工作要点 </a> </li> <li class=md-nav__item> <a href=#822-hdfs-ha class=md-nav__link> 8.2.2 HDFS-HA自动故障转移工作机制 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#83-hdfs-ha class=md-nav__link> 8.3 HDFS-HA集群配置 </a> <nav class=md-nav aria-label="8.3 HDFS-HA集群配置"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#831 class=md-nav__link> 8.3.1 环境准备 </a> </li> <li class=md-nav__item> <a href=#832 class=md-nav__link> 8.3.2 规划集群 </a> </li> <li class=md-nav__item> <a href=#833-zookeeper class=md-nav__link> 8.3.3 配置Zookeeper集群 </a> </li> <li class=md-nav__item> <a href=#834-hdfs-ha class=md-nav__link> 8.3.4 配置HDFS-HA集群 </a> </li> <li class=md-nav__item> <a href=#835-hdfs-ha class=md-nav__link> 8.3.5 启动HDFS-HA集群 </a> </li> <li class=md-nav__item> <a href=#836-hdfs-ha class=md-nav__link> 8.3.6 配置HDFS-HA自动故障转移 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#84-yarn-ha class=md-nav__link> 8.4 YARN-HA配置 </a> <nav class=md-nav aria-label="8.4 YARN-HA配置"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#841-yarn-ha class=md-nav__link> 8.4.1 YARN-HA工作机制 </a> </li> <li class=md-nav__item> <a href=#842-yarn-ha class=md-nav__link> 8.4.2 配置YARN-HA集群 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#85-hdfs-federation class=md-nav__link> 8.5 HDFS Federation架构设计 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../Hadoop-MapReduce/ title=MapReduce class=md-nav__link> MapReduce </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-7-2 type=checkbox id=nav-7-2> <label class=md-nav__link for=nav-7-2> Spark <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=Spark data-md-level=2> <label class=md-nav__title for=nav-7-2> <span class="md-nav__icon md-icon"></span> Spark </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../Spark%E5%9F%BA%E7%A1%80/ title=Spark基础 class=md-nav__link> Spark基础 </a> </li> <li class=md-nav__item> <a href=../SparkCore/ title=SparkCore class=md-nav__link> SparkCore </a> </li> <li class=md-nav__item> <a href=../SparkSql/ title=SparkSql class=md-nav__link> SparkSql </a> </li> <li class=md-nav__item> <a href=../SparkStreaming/ title=SparkStreaming class=md-nav__link> SparkStreaming </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../Flink/ title=Flink class=md-nav__link> Flink </a> </li> <li class=md-nav__item> <a href=../Zookeeper/ title=Zookeeper class=md-nav__link> Zookeeper </a> </li> <li class=md-nav__item> <a href=../Hbase/ title=HBase class=md-nav__link> HBase </a> </li> <li class=md-nav__item> <a href=../Hive/ title=Hive class=md-nav__link> Hive </a> </li> <li class=md-nav__item> <a href=../Kafka/ title=Kafka class=md-nav__link> Kafka </a> </li> <li class=md-nav__item> <a href=../Flume/ title=Flume class=md-nav__link> Flume </a> </li> <li class=md-nav__item> <a href=../Sqoop/ title=Sqoop class=md-nav__link> Sqoop </a> </li> <li class=md-nav__item> <a href=../Oozie/ title=Oozie class=md-nav__link> Oozie </a> </li> <li class=md-nav__item> <a href=../Azkaban/ title=Azkaban class=md-nav__link> Azkaban </a> </li> <li class=md-nav__item> <a href=../Kylin/ title=Kylin class=md-nav__link> Kylin </a> </li> <li class=md-nav__item> <a href=../Presto/ title=Presto class=md-nav__link> Presto </a> </li> <li class=md-nav__item> <a href=../ELK/ title=ELK class=md-nav__link> ELK </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-8 type=checkbox id=nav-8> <label class=md-nav__link for=nav-8> 数据库 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=数据库 data-md-level=1> <label class=md-nav__title for=nav-8> <span class="md-nav__icon md-icon"></span> 数据库 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Mysql%E5%AE%89%E8%A3%85/ title=Mysql安装 class=md-nav__link> Mysql安装 </a> </li> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Oracle%E5%AE%89%E8%A3%85/ title=Oracle安装 class=md-nav__link> Oracle安装 </a> </li> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Redis%E5%AE%89%E8%A3%85/ title=Redis安装 class=md-nav__link> Redis安装 </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-9 type=checkbox id=nav-9> <label class=md-nav__link for=nav-9> 项目开发 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=项目开发 data-md-level=1> <label class=md-nav__title for=nav-9> <span class="md-nav__icon md-icon"></span> 项目开发 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/Web%E5%BC%80%E5%8F%91/ title=Web开发 class=md-nav__link> Web开发 </a> </li> <li class=md-nav__item> <a href=../../%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/%E5%AE%89%E5%8D%93%E5%BC%80%E5%8F%91/ title=安卓开发 class=md-nav__link> 安卓开发 </a> </li> <li class=md-nav__item> <a href=../../%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/PC%E7%AB%AF%E5%BC%80%E5%8F%91/ title=PC端开发 class=md-nav__link> PC端开发 </a> </li> <li class=md-nav__item> <a href=../../%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%BC%80%E5%8F%91/ title=大数据开发 class=md-nav__link> 大数据开发 </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-10 type=checkbox id=nav-10> <label class=md-nav__link for=nav-10> 必备技能 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=必备技能 data-md-level=1> <label class=md-nav__title for=nav-10> <span class="md-nav__icon md-icon"></span> 必备技能 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Git/ title=Git class=md-nav__link> Git </a> </li> <li class=md-nav__item> <a href=../../%E5%BF%85%E5%A4%87%E6%8A%80%E6%9C%AF/Zabbix5/ title=Zabbix class=md-nav__link> Zabbix </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-11 type=checkbox id=nav-11> <label class=md-nav__link for=nav-11> 常用工具 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=常用工具 data-md-level=1> <label class=md-nav__title for=nav-11> <span class="md-nav__icon md-icon"></span> 常用工具 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/IDEA/ title=IDEA class=md-nav__link> IDEA </a> </li> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/Wiki/ title=Wiki class=md-nav__link> Wiki </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle" data-md-toggle=nav-12 type=checkbox id=nav-12> <label class=md-nav__link for=nav-12> 面试题库 <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav aria-label=面试题库 data-md-level=1> <label class=md-nav__title for=nav-12> <span class="md-nav__icon md-icon"></span> 面试题库 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/IDEA/ title=编程语言 class=md-nav__link> 编程语言 </a> </li> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/IDEA/ title=系统操作 class=md-nav__link> 系统操作 </a> </li> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/IDEA/ title=数据库 class=md-nav__link> 数据库 </a> </li> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/IDEA/ title=大数据 class=md-nav__link> 大数据 </a> </li> <li class=md-nav__item> <a href=../../%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/IDEA/ title=项目 class=md-nav__link> 项目 </a> </li> </ul> </nav> </li> </ul> </nav> </div> </div> </div> <div class="md-sidebar md-sidebar--secondary" data-md-component=toc> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--secondary" aria-label=目录> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> 目录 </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=#1-hdfs class=md-nav__link> 第1章 HDFS概述 </a> </li> <li class=md-nav__item> <a href=#11-hdfs class=md-nav__link> 1.1 HDFS产出背景及定义 </a> </li> <li class=md-nav__item> <a href=#12-hdfs class=md-nav__link> 1.2 HDFS优缺点 </a> </li> <li class=md-nav__item> <a href=#13-hdfs class=md-nav__link> 1.3 HDFS组成架构 </a> </li> <li class=md-nav__item> <a href=#14-hdfs class=md-nav__link> 1.4 HDFS文件块大小 </a> </li> <li class=md-nav__item> <a href=#2-hdfsshell class=md-nav__link> 第2章 HDFS的Shell操作（开发重点） </a> </li> <li class=md-nav__item> <a href=#3-hdfs class=md-nav__link> 第3章 HDFS客户端操作（开发重点） </a> </li> <li class=md-nav__item> <a href=#31-hdfs class=md-nav__link> 3.1 HDFS客户端环境准备 </a> </li> <li class=md-nav__item> <a href=#32-hdfsapi class=md-nav__link> 3.2 HDFS的API操作 </a> <nav class=md-nav aria-label="3.2 HDFS的API操作"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#321-hdfs class=md-nav__link> 3.2.1 HDFS文件上传（测试参数优先级） </a> </li> <li class=md-nav__item> <a href=#322-hdfs class=md-nav__link> 3.2.2 HDFS文件下载 </a> </li> <li class=md-nav__item> <a href=#323-hdfs class=md-nav__link> 3.2.3 HDFS文件夹删除 </a> </li> <li class=md-nav__item> <a href=#324-hdfs class=md-nav__link> 3.2.4 HDFS文件名更改 </a> </li> <li class=md-nav__item> <a href=#325-hdfs class=md-nav__link> 3.2.5 HDFS文件详情查看 </a> </li> <li class=md-nav__item> <a href=#326-hdfs class=md-nav__link> 3.2.6 HDFS文件和文件夹判断 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#33-hdfsio class=md-nav__link> 3.3 HDFS的I/O流操作 </a> <nav class=md-nav aria-label="3.3 HDFS的I/O流操作"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#331-hdfs class=md-nav__link> 3.3.1 HDFS文件上传 </a> </li> <li class=md-nav__item> <a href=#332-hdfs class=md-nav__link> 3.3.2 HDFS文件下载 </a> </li> <li class=md-nav__item> <a href=#333 class=md-nav__link> 3.3.3 定位文件读取 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#4-hdfs class=md-nav__link> 第4章 HDFS的数据流 </a> </li> <li class=md-nav__item> <a href=#41-hdfs class=md-nav__link> 4.1 HDFS写数据流程 </a> <nav class=md-nav aria-label="4.1 HDFS写数据流程"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#411 class=md-nav__link> 4.1.1 剖析文件写入 </a> </li> <li class=md-nav__item> <a href=#412- class=md-nav__link> 4.1.2 网络拓扑-节点距离计算 </a> </li> <li class=md-nav__item> <a href=#413 class=md-nav__link> 4.1.3 机架感知（副本存储节点选择） </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#42-hdfs class=md-nav__link> 4.2 HDFS读数据流程 </a> </li> <li class=md-nav__item> <a href=#5-namenodesecondarynamenode class=md-nav__link> 第5章 NameNode和SecondaryNameNode（重点） </a> </li> <li class=md-nav__item> <a href=#51-nn2nn class=md-nav__link> 5.1 NN和2NN工作机制 </a> </li> <li class=md-nav__item> <a href=#52-fsimageedits class=md-nav__link> 5.2 Fsimage和Edits解析 </a> </li> <li class=md-nav__item> <a href=#53-checkpoint class=md-nav__link> 5.3 CheckPoint时间设置 </a> </li> <li class=md-nav__item> <a href=#54-namenode class=md-nav__link> 5.4 NameNode故障处理 </a> </li> <li class=md-nav__item> <a href=#55 class=md-nav__link> 5.5 集群安全模式 </a> </li> <li class=md-nav__item> <a href=#56-namenode class=md-nav__link> 5.6 NameNode多目录配置 </a> </li> <li class=md-nav__item> <a href=#6-datanode class=md-nav__link> 第6章 DataNode </a> </li> <li class=md-nav__item> <a href=#61-datanode class=md-nav__link> 6.1 DataNode工作机制 </a> </li> <li class=md-nav__item> <a href=#62 class=md-nav__link> 6.2 数据完整性 </a> </li> <li class=md-nav__item> <a href=#63 class=md-nav__link> 6.3 掉线时限参数设置 </a> </li> <li class=md-nav__item> <a href=#64 class=md-nav__link> 6.4 服役新数据节点 </a> </li> <li class=md-nav__item> <a href=#65 class=md-nav__link> 6.5 退役旧数据节点 </a> <nav class=md-nav aria-label="6.5 退役旧数据节点"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#651 class=md-nav__link> 6.5.1 添加白名单 </a> </li> <li class=md-nav__item> <a href=#652 class=md-nav__link> 6.5.2 黑名单退役 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#66-datanode class=md-nav__link> 6.6 Datanode多目录配置 </a> </li> <li class=md-nav__item> <a href=#7-hdfs-2x class=md-nav__link> 第7章 HDFS 2.X新特性 </a> </li> <li class=md-nav__item> <a href=#71 class=md-nav__link> 7.1 集群间数据拷贝 </a> </li> <li class=md-nav__item> <a href=#72 class=md-nav__link> 7.2 小文件存档 </a> </li> <li class=md-nav__item> <a href=#73 class=md-nav__link> 7.3 回收站 </a> </li> <li class=md-nav__item> <a href=#74 class=md-nav__link> 7.4 快照管理 </a> </li> <li class=md-nav__item> <a href=#8-hdfs-ha class=md-nav__link> 第8章 HDFS HA高可用 </a> </li> <li class=md-nav__item> <a href=#81-ha class=md-nav__link> 8.1 HA概述 </a> </li> <li class=md-nav__item> <a href=#82-hdfs-ha class=md-nav__link> 8.2 HDFS-HA工作机制 </a> <nav class=md-nav aria-label="8.2 HDFS-HA工作机制"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#821-hdfs-ha class=md-nav__link> 8.2.1 HDFS-HA工作要点 </a> </li> <li class=md-nav__item> <a href=#822-hdfs-ha class=md-nav__link> 8.2.2 HDFS-HA自动故障转移工作机制 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#83-hdfs-ha class=md-nav__link> 8.3 HDFS-HA集群配置 </a> <nav class=md-nav aria-label="8.3 HDFS-HA集群配置"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#831 class=md-nav__link> 8.3.1 环境准备 </a> </li> <li class=md-nav__item> <a href=#832 class=md-nav__link> 8.3.2 规划集群 </a> </li> <li class=md-nav__item> <a href=#833-zookeeper class=md-nav__link> 8.3.3 配置Zookeeper集群 </a> </li> <li class=md-nav__item> <a href=#834-hdfs-ha class=md-nav__link> 8.3.4 配置HDFS-HA集群 </a> </li> <li class=md-nav__item> <a href=#835-hdfs-ha class=md-nav__link> 8.3.5 启动HDFS-HA集群 </a> </li> <li class=md-nav__item> <a href=#836-hdfs-ha class=md-nav__link> 8.3.6 配置HDFS-HA自动故障转移 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#84-yarn-ha class=md-nav__link> 8.4 YARN-HA配置 </a> <nav class=md-nav aria-label="8.4 YARN-HA配置"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#841-yarn-ha class=md-nav__link> 8.4.1 YARN-HA工作机制 </a> </li> <li class=md-nav__item> <a href=#842-yarn-ha class=md-nav__link> 8.4.2 配置YARN-HA集群 </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#85-hdfs-federation class=md-nav__link> 8.5 HDFS Federation架构设计 </a> </li> </ul> </nav> </div> </div> </div> <div class=md-content> <article class="md-content__inner md-typeset"> <h1 id=hadoop-hdfs><center>Hadoop-HDFS</center></h1> <h2 id=1-hdfs>第1章 HDFS概述</h2> <h2 id=11-hdfs>1.1 HDFS产出背景及定义</h2> <h2 id=12-hdfs>1.2 HDFS优缺点</h2> <h2 id=13-hdfs>1.3 HDFS组成架构</h2> <h2 id=14-hdfs>1.4 HDFS文件块大小</h2> <h2 id=2-hdfsshell>第2章 HDFS的Shell操作（开发重点）</h2> <p>1．基本语法</p> <p>bin/hadoop fs 具体命令 OR bin/hdfs dfs 具体命令</p> <p>dfs是fs的实现类。</p> <p>2．命令大全</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hadoop fs</p> <p>[-appendToFile \&lt;localsrc> &hellip; \&lt;dst>]</p> <p>[-cat [-ignoreCrc] \&lt;src> &hellip;]</p> <p>[-checksum \&lt;src> &hellip;]</p> <p>[-chgrp [-R] GROUP PATH&hellip;]</p> <p>[-chmod [-R] \&lt;MODE[,MODE]&hellip; | OCTALMODE> PATH&hellip;]</p> <p>[-chown [-R] [OWNER][:[GROUP]] PATH&hellip;]</p> <p>[-copyFromLocal [-f] [-p] \&lt;localsrc> &hellip; \&lt;dst>]</p> <p>[-copyToLocal [-p] [-ignoreCrc] [-crc] \&lt;src> &hellip; \&lt;localdst>]</p> <p>[-count [-q] \&lt;path> &hellip;]</p> <p>[-cp [-f] [-p] \&lt;src> &hellip; \&lt;dst>]</p> <p>[-createSnapshot \&lt;snapshotDir> [\&lt;snapshotName>]]</p> <p>[-deleteSnapshot \&lt;snapshotDir> \&lt;snapshotName>]</p> <p>[-df [-h] [\&lt;path> &hellip;]]</p> <p>[-du [-s] [-h] \&lt;path> &hellip;]</p> <p>[-expunge]</p> <p>[-get [-p] [-ignoreCrc] [-crc] \&lt;src> &hellip; \&lt;localdst>]</p> <p>[-getfacl [-R] \&lt;path>]</p> <p>[-getmerge [-nl] \&lt;src> \&lt;localdst>]</p> <p>[-help [cmd &hellip;]]</p> <p>[-ls [-d] [-h] [-R] [\&lt;path> &hellip;]]</p> <p>[-mkdir [-p] \&lt;path> &hellip;]</p> <p>[-moveFromLocal \&lt;localsrc> &hellip; \&lt;dst>]</p> <p>[-moveToLocal \&lt;src> \&lt;localdst>]</p> <p>[-mv \&lt;src> &hellip; \&lt;dst>]</p> <p>[-put [-f] [-p] \&lt;localsrc> &hellip; \&lt;dst>]</p> <p>[-renameSnapshot \&lt;snapshotDir> \&lt;oldName> \&lt;newName>]</p> <p>[-rm [-f] [-r|-R] [-skipTrash] \&lt;src> &hellip;]</p> <p>[-rmdir [&ndash;ignore-fail-on-non-empty] \&lt;dir> &hellip;]</p> <p>[-setfacl [-R] [{-b|-k} {-m|-x \&lt;acl_spec>} \&lt;path>]|[&ndash;set \&lt;acl_spec> \&lt;path>]]</p> <p>[-setrep [-R] [-w] \&lt;rep> \&lt;path> &hellip;]</p> <p>[-stat [format] \&lt;path> &hellip;]</p> <p>[-tail [-f] \&lt;file>]</p> <p>[-test -[defsz] \&lt;path>]</p> <p>[-text [-ignoreCrc] \&lt;src> &hellip;]</p> <p>[-touchz \&lt;path> &hellip;]</p> <p>[-usage [cmd &hellip;]]</p> </blockquote> <p>3．常用命令实操</p> <p>（0）启动Hadoop集群（方便后续的测试）</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh</p> <p>[atguigu\@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh</p> </blockquote> <p>（1）-help：输出这个命令参数</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -help rm</p> </blockquote> <p>（2）-ls: 显示目录信息</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -ls /</p> </blockquote> <p>（3）-mkdir：在HDFS上创建目录</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -mkdir -p /sanguo/shuguo</p> </blockquote> <p>（4）-moveFromLocal：从本地剪切粘贴到HDFS</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ touch kongming.txt</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -moveFromLocal ./kongming.txt /sanguo/shuguo</p> </blockquote> <p>（5）-appendToFile：追加一个文件到已经存在的文件末尾</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ touch liubei.txt</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ vi liubei.txt</p> <p>输入</p> <p>san gu mao lu</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt</p> </blockquote> <p>（6）-cat：显示文件内容</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -cat /sanguo/shuguo/kongming.txt</p> </blockquote> <p>（7）-chgrp 、-chmod、-chown：Linux文件系统中的用法一样，修改文件所属权限</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -chmod 666 /sanguo/shuguo/kongming.txt</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -chown atguigu:atguigu /sanguo/shuguo/kongming.txt</p> </blockquote> <p>（8）-copyFromLocal：从本地文件系统中拷贝文件到HDFS路径去</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -copyFromLocal README.txt /</p> </blockquote> <p>（9）-copyToLocal：从HDFS拷贝到本地</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -copyToLocal /sanguo/shuguo/kongming.txt ./</p> </blockquote> <p>（10）-cp ：从HDFS的一个路径拷贝到HDFS的另一个路径</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt</p> </blockquote> <p>（11）-mv：在HDFS目录中移动文件</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -mv /zhuge.txt /sanguo/shuguo/</p> </blockquote> <p>（12）-get：等同于copyToLocal，就是从HDFS下载文件到本地</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -get /sanguo/shuguo/kongming.txt ./</p> </blockquote> <p>（13）-getmerge：合并下载多个文件，比如HDFS的目录 /user/atguigu/test下有多个文件:log.1, log.2,log.3,&hellip;</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -getmerge /user/atguigu/test/* ./zaiyiqi.txt</p> </blockquote> <p>（14）-put：等同于copyFromLocal</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -put ./zaiyiqi.txt /user/atguigu/test/</p> </blockquote> <p>（15）-tail：显示一个文件的末尾</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -tail /sanguo/shuguo/kongming.txt</p> </blockquote> <p>（16）-rm：删除文件或文件夹</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -rm /user/atguigu/test/jinlian2.txt</p> </blockquote> <p>（17）-rmdir：删除空目录</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -mkdir /test</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -rmdir /test</p> </blockquote> <p>（18）-du统计文件夹的大小信息</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -du -s -h /user/atguigu/test</p> <p>2.7 K /user/atguigu/test</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -du -h /user/atguigu/test</p> <p>1.3 K /user/atguigu/test/README.txt</p> <p>15 /user/atguigu/test/jinlian.txt</p> <p>1.4 K /user/atguigu/test/zaiyiqi.txt</p> </blockquote> <p>（19）-setrep：设置HDFS中文件的副本数量</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt</p> </blockquote> <p><img alt=1516695160(1) src=3f49db0d4950d11a1da511a7464a88d5.png></p> <p>图3-3 HDFS副本数量</p> <p>这里设置的副本数只是记录在NameNode的元数据中，是否真的会有这么多副本，还得看DataNode的数量。因为目前只有3台设备，最多也就3个副本，只有节点数的增加到10台时，副本数才能达到10。</p> <h2 id=3-hdfs>第3章 HDFS客户端操作（开发重点）</h2> <h2 id=31-hdfs>3.1 HDFS客户端环境准备</h2> <p>1．根据自己电脑的操作系统拷贝对应的编译后的hadoop jar包到非中文路径（例如：D:\Develop\hadoop-2.7.2），如图3-4所示。</p> <p><img alt src=aaecd9da886f5010454461e60b645407.png></p> <p>图3-4 编译后的hadoop jar包</p> <p>2．配置HADOOP_HOME环境变量，如图3-5所示。</p> <p><img alt src=9880c581217c25a7eae2f08cb3cb90dd.png></p> <p>图3-5 配置HADOOP_HOME环境变量</p> <ol> <li>配置Path环境变量，如图3-6所示。</li> </ol> <p><img alt=1516417967(1) src=4e5d8eacf9bf68d8070bdbc2033199e1.png></p> <p>图3-6 配置Path环境变量</p> <p>4．创建一个Maven工程HdfsClientDemo</p> <p>5．导入相应的依赖坐标+日志添加</p> <blockquote> <p>\&lt;dependencies></p> <p>\&lt;dependency></p> <p>\&lt;groupId>junit\&lt;/groupId></p> <p>\&lt;artifactId>junit\&lt;/artifactId></p> <p>\&lt;version>RELEASE\&lt;/version></p> <p>\&lt;/dependency></p> <p>\&lt;dependency></p> <p>\&lt;groupId>org.apache.logging.log4j\&lt;/groupId></p> <p>\&lt;artifactId>log4j-core\&lt;/artifactId></p> <p>\&lt;version>2.8.2\&lt;/version></p> <p>\&lt;/dependency></p> <p>\&lt;dependency></p> <p>\&lt;groupId>org.apache.hadoop\&lt;/groupId></p> <p>\&lt;artifactId>hadoop-common\&lt;/artifactId></p> <p>\&lt;version>2.7.2\&lt;/version></p> <p>\&lt;/dependency></p> <p>\&lt;dependency></p> <p>\&lt;groupId>org.apache.hadoop\&lt;/groupId></p> <p>\&lt;artifactId>hadoop-client\&lt;/artifactId></p> <p>\&lt;version>2.7.2\&lt;/version></p> <p>\&lt;/dependency></p> <p>\&lt;dependency></p> <p>\&lt;groupId>org.apache.hadoop\&lt;/groupId></p> <p>\&lt;artifactId>hadoop-hdfs\&lt;/artifactId></p> <p>\&lt;version>2.7.2\&lt;/version></p> <p>\&lt;/dependency></p> <p>\&lt;dependency></p> <p>\&lt;groupId>jdk.tools\&lt;/groupId></p> <p>\&lt;artifactId>jdk.tools\&lt;/artifactId></p> <p>\&lt;version>1.8\&lt;/version></p> <p>\&lt;scope>system\&lt;/scope></p> <p>\&lt;systemPath>${JAVA_HOME}/lib/tools.jar\&lt;/systemPath></p> <p>\&lt;/dependency></p> <p>\&lt;/dependencies></p> </blockquote> <p>注意：如果Eclipse/Idea打印不出日志，在控制台上只显示</p> <blockquote> <p>1.log4j:WARN No appenders could be found for logger (org.apache.hadoop.util.Shell).  </p> <p>2.log4j:WARN Please initialize the log4j system properly.  </p> <p>3.log4j:WARN See <a href=http://logging.apache.org/log4j/1.2/faq.html>http://logging.apache.org/log4j/1.2/faq.html</a>#noconfig for more info.</p> </blockquote> <p>需要在项目的src/main/resources目录下，新建一个文件，命名为“log4j.properties”，在文件中填入</p> <blockquote> <p>log4j.rootLogger=INFO, stdout</p> <p>log4j.appender.stdout=org.apache.log4j.ConsoleAppender</p> <p>log4j.appender.stdout.layout=org.apache.log4j.PatternLayout</p> <p>log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n</p> <p>log4j.appender.logfile=org.apache.log4j.FileAppender</p> <p>log4j.appender.logfile.File=target/spring.log</p> <p>log4j.appender.logfile.layout=org.apache.log4j.PatternLayout</p> <p>log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n</p> </blockquote> <p>6．创建包名：com.atguigu.hdfs</p> <p>7．创建HdfsClient类</p> <blockquote> <p>public class HdfsClient{</p> <p>\@Test</p> <p>public void testMkdirs() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>// 配置在集群上运行</p> <p>// configuration.set(&ldquo;fs.defaultFS&rdquo;, &ldquo;hdfs://hadoop102:9000&rdquo;);</p> <p>// FileSystem fs = FileSystem.get(configuration);</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 创建目录</p> <p>fs.mkdirs(new Path(&ldquo;/1108/daxian/banzhang&rdquo;));</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>}</p> <p>}</p> </blockquote> <p>8．执行程序</p> <p>运行时需要配置用户名称，如图3-7所示</p> <p><img alt src=5603d89bd4d7cd4683ff9b6aa2455ffa.png></p> <p>图3-7 配置用户名称</p> <p>客户端去操作HDFS时，是有一个用户身份的。默认情况下，HDFS客户端API会从JVM中获取一个参数来作为自己的用户身份：-DHADOOP_USER_NAME=atguigu，atguigu为用户名称。</p> <h2 id=32-hdfsapi>3.2 HDFS的API操作</h2> <h3 id=321-hdfs>3.2.1 HDFS文件上传（测试参数优先级）</h3> <p>1．编写源代码</p> <table> <thead> <tr> <th>\@Test</th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <blockquote> <p>public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>configuration.set(&ldquo;dfs.replication&rdquo;, &ldquo;2&rdquo;);</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 上传文件</p> <p>fs.copyFromLocalFile(new Path(&ldquo;e:/banzhang.txt&rdquo;), new Path(&ldquo;/banzhang.txt&rdquo;));</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>System.out.println(&ldquo;over&rdquo;);</p> <p>}</p> </blockquote> <p>2．将hdfs-site.xml拷贝到项目的根目录下</p> <table> <thead> <tr> <th>\&lt;?xml version=&rdquo;1.0&rdquo; encoding=&rdquo;UTF-8&rdquo;?></th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <blockquote> <p>\&lt;?xml-stylesheet type=&rdquo;text/xsl&rdquo; href=&rdquo;configuration.xsl&rdquo;?></p> <p>\&lt;configuration></p> <p>\&lt;property></p> <p>\&lt;name>dfs.replication\&lt;/name></p> <p>\&lt;value>1\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;/configuration></p> </blockquote> <p>3．参数优先级</p> <p>参数优先级排序：（1）客户端代码中设置的值 >（2）*ClassPath*下的用户自定义配置文件 >（3）然后是服务器的默认配置</p> <h3 id=322-hdfs>3.2.2 HDFS文件下载</h3> <blockquote> <p>\@Test</p> <p>public void testCopyToLocalFile() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 执行下载操作</p> <p>// boolean delSrc 指是否将原文件删除</p> <p>// Path src 指要下载的文件路径</p> <p>// Path dst 指将文件下载到的路径</p> <p>// boolean useRawLocalFileSystem 是否开启文件校验</p> <p>fs.copyToLocalFile(false, new Path(&ldquo;/banzhang.txt&rdquo;), new Path(&ldquo;e:/banhua.txt&rdquo;), true);</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>}</p> </blockquote> <h3 id=323-hdfs>3.2.3 HDFS文件夹删除</h3> <blockquote> <p>\@Test</p> <p>public void testDelete() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 执行删除</p> <p>fs.delete(new Path(&ldquo;/0508/&rdquo;), true);</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>}</p> </blockquote> <h3 id=324-hdfs>3.2.4 HDFS文件名更改</h3> <blockquote> <p>\@Test</p> <p>public void testRename() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 修改文件名称</p> <p>fs.rename(new Path(&ldquo;/banzhang.txt&rdquo;), new Path(&ldquo;/banhua.txt&rdquo;));</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>}</p> </blockquote> <h3 id=325-hdfs>3.2.5 HDFS文件详情查看</h3> <p>查看文件名称、权限、长度、块信息</p> <blockquote> <p>\@Test</p> <p>public void testListFiles() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 获取文件详情</p> <p>RemoteIterator\&lt;LocatedFileStatus> listFiles = fs.listFiles(new Path(&ldquo;/&rdquo;), true);</p> <p>while(listFiles.hasNext()){</p> <p>LocatedFileStatus status = listFiles.next();</p> <p>// 输出详情</p> <p>// 文件名称</p> <p>System.out.println(status.getPath().getName());</p> <p>// 长度</p> <p>System.out.println(status.getLen());</p> <p>// 权限</p> <p>System.out.println(status.getPermission());</p> <p>// 分组</p> <p>System.out.println(status.getGroup());</p> <p>// 获取存储的块信息</p> <p>BlockLocation[] blockLocations = status.getBlockLocations();</p> <p>for (BlockLocation blockLocation : blockLocations) {</p> <p>// 获取块存储的主机节点</p> <p>String[] hosts = blockLocation.getHosts();</p> <p>for (String host : hosts) {</p> <p>System.out.println(host);</p> <p>}</p> <p>}</p> <p>System.out.println(&ldquo;-----------班长的分割线----------&ldquo;);</p> <p>}</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>}</p> </blockquote> <h3 id=326-hdfs>3.2.6 HDFS文件和文件夹判断</h3> <blockquote> <p>\@Test</p> <p>public void testListStatus() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件配置信息</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 判断是文件还是文件夹</p> <p>FileStatus[] listStatus = fs.listStatus(new Path(&ldquo;/&rdquo;));</p> <p>for (FileStatus fileStatus : listStatus) {</p> <p>// 如果是文件</p> <p>if (fileStatus.isFile()) {</p> <p>System.out.println(&ldquo;f:&rdquo;+fileStatus.getPath().getName());</p> <p>}else {</p> <p>System.out.println(&ldquo;d:&rdquo;+fileStatus.getPath().getName());</p> <p>}</p> <p>}</p> <p>// 3 关闭资源</p> <p>fs.close();</p> <p>}</p> </blockquote> <h2 id=33-hdfsio>3.3 HDFS的I/O流操作</h2> <p>上面我们学的API操作HDFS系统都是框架封装好的。那么如果我们想自己实现上述API的操作该怎么实现呢？</p> <p>我们可以采用IO流的方式实现数据的上传和下载。</p> <h3 id=331-hdfs>3.3.1 HDFS文件上传</h3> <p>1．需求：把本地e盘上的banhua.txt文件上传到HDFS根目录</p> <p>2．编写代码</p> <blockquote> <p>\@Test</p> <p>public void putFileToHDFS() throws IOException, InterruptedException, URISyntaxException {</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 创建输入流</p> <p>FileInputStream fis = new FileInputStream(new File(&ldquo;e:/banhua.txt&rdquo;));</p> <p>// 3 获取输出流</p> <p>FSDataOutputStream fos = fs.create(new Path(&ldquo;/banhua.txt&rdquo;));</p> <p>// 4 流对拷</p> <p>IOUtils.copyBytes(fis, fos, configuration);</p> <p>// 5 关闭资源</p> <p>IOUtils.closeStream(fos);</p> <p>IOUtils.closeStream(fis);</p> <p>fs.close();</p> <p>}</p> </blockquote> <h3 id=332-hdfs>3.3.2 HDFS文件下载</h3> <p>1．需求：从HDFS上下载banhua.txt文件到本地e盘上</p> <p>2．编写代码</p> <blockquote> <p>// 文件下载</p> <p>\@Test</p> <p>public void getFileFromHDFS() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 获取输入流</p> <p>FSDataInputStream fis = fs.open(new Path(&ldquo;/banhua.txt&rdquo;));</p> <p>// 3 获取输出流</p> <p>FileOutputStream fos = new FileOutputStream(new File(&ldquo;e:/banhua.txt&rdquo;));</p> <p>// 4 流的对拷</p> <p>IOUtils.copyBytes(fis, fos, configuration);</p> <p>// 5 关闭资源</p> <p>IOUtils.closeStream(fos);</p> <p>IOUtils.closeStream(fis);</p> <p>fs.close();</p> <p>}</p> </blockquote> <h3 id=333>3.3.3 定位文件读取</h3> <p>1．需求：分块读取HDFS上的大文件，比如根目录下的/hadoop-2.7.2.tar.gz</p> <p>2．编写代码</p> <p>（1）下载第一块</p> <blockquote> <p>\@Test</p> <p>public void readFileSeek1() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 获取输入流</p> <p>FSDataInputStream fis = fs.open(new Path(&ldquo;/hadoop-2.7.2.tar.gz&rdquo;));</p> <p>// 3 创建输出流</p> <p>FileOutputStream fos = new FileOutputStream(new File(&ldquo;e:/hadoop-2.7.2.tar.gz.part1&rdquo;));</p> <p>// 4 流的拷贝</p> <p>byte[] buf = new byte[1024];</p> <p>for(int i =0 ; i \&lt; 1024 * 128; i++){</p> <p>fis.read(buf);</p> <p>fos.write(buf);</p> <p>}</p> <p>// 5关闭资源</p> <p>IOUtils.closeStream(fis);</p> <p>IOUtils.closeStream(fos);</p> <p>fs.close();</p> <p>}</p> </blockquote> <p>（2）下载第二块</p> <blockquote> <p>\@Test</p> <p>public void readFileSeek2() throws IOException, InterruptedException, URISyntaxException{</p> <p>// 1 获取文件系统</p> <p>Configuration configuration = new Configuration();</p> <p>FileSystem fs = FileSystem.get(new URI(&ldquo;hdfs://hadoop102:9000&rdquo;), configuration, &ldquo;atguigu&rdquo;);</p> <p>// 2 打开输入流</p> <p>FSDataInputStream fis = fs.open(new Path(&ldquo;/hadoop-2.7.2.tar.gz&rdquo;));</p> <p>// 3 定位输入数据位置</p> <p>fis.seek(1024*1024*128);</p> <p>// 4 创建输出流</p> <p>FileOutputStream fos = new FileOutputStream(new File(&ldquo;e:/hadoop-2.7.2.tar.gz.part2&rdquo;));</p> <p>// 5 流的对拷</p> <p>IOUtils.copyBytes(fis, fos, configuration);</p> <p>// 6 关闭资源</p> <p>IOUtils.closeStream(fis);</p> <p>IOUtils.closeStream(fos);</p> <p>}</p> </blockquote> <p>（3）合并文件</p> <blockquote> <p>在Window命令窗口中进入到目录E:\，然后执行如下命令，对数据进行合并</p> <p>type hadoop-2.7.2.tar.gz.part2 >> hadoop-2.7.2.tar.gz.part1</p> </blockquote> <p>合并完成后，将hadoop-2.7.2.tar.gz.part1重新命名为hadoop-2.7.2.tar.gz。解压发现该tar包非常完整。</p> <h2 id=4-hdfs>第4章 HDFS的数据流</h2> <h2 id=41-hdfs>4.1 HDFS写数据流程</h2> <h3 id=411>4.1.1 剖析文件写入</h3> <p>HDFS写数据流程，如图3-8所示。</p> <p>图3-8 配置用户名称</p> <p>1）客户端通过Distributed FileSystem模块向NameNode请求上传文件，NameNode检查目标文件是否已存在，父目录是否存在。</p> <p>2）NameNode返回是否可以上传。</p> <p>3）客户端请求第一个 Block上传到哪几个DataNode服务器上。</p> <p>4）NameNode返回3个DataNode节点，分别为dn1、dn2、dn3。</p> <p>5）客户端通过FSDataOutputStream模块请求dn1上传数据，dn1收到请求会继续调用dn2，然后dn2调用dn3，将这个通信管道建立完成。</p> <p>6）dn1、dn2、dn3逐级应答客户端。</p> <p>7）客户端开始往dn1上传第一个Block（先从磁盘读取数据放到一个本地内存缓存），以Packet为单位，dn1收到一个Packet就会传给dn2，dn2传给dn3；dn1每传一个packet会放入一个应答队列等待应答。</p> <p>8）当一个Block传输完成之后，客户端再次请求NameNode上传第二个Block的服务器。（重复执行3-7步）。</p> <h3 id=412->4.1.2 网络拓扑-节点距离计算</h3> <p>在HDFS写数据的过程中，NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢？</p> <p>节点距离：两个节点到达最近的共同祖先的距离总和。</p> <p>图3-9 网络拓扑概念</p> <p>例如，假设有数据中心d1机架r1中的节点n1。该节点可以表示为/d1/r1/n1。利用这种标记，这里给出四种距离描述，如图3-9所示。</p> <p>大家算一算每两个节点之间的距离，如图3-10所示。</p> <p><img alt src=d52c7ff1dfa98e408a56a10e97bbf250.png></p> <p>图3-10 网络拓扑</p> <h3 id=413>4.1.3 机架感知（副本存储节点选择）</h3> <ol> <li>官方ip地址</li> </ol> <p>机架感知说明</p> <p><em><a href=http://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html>http://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html</a>#Data_Replication</em></p> <blockquote> <p>For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on one node in the local rack, another on a different node in the local rack, and the last on a different node in a different rack.</p> </blockquote> <ol> <li>Hadoop2.7.2副本节点选择</li> </ol> <h2 id=42-hdfs>4.2 HDFS读数据流程</h2> <p>HDFS的读数据流程，如图3-13所示。</p> <p>图3-13 HDFS读数据流程</p> <p>1）客户端通过Distributed FileSystem向NameNode请求下载文件，NameNode通过查询元数据，找到文件块所在的DataNode地址。</p> <p>2）挑选一台DataNode（就近原则，然后随机）服务器，请求读取数据。</p> <p>3）DataNode开始传输数据给客户端（从磁盘里面读取数据输入流，以Packet为单位来做校验）。</p> <p>4）客户端以Packet为单位接收，先在本地缓存，然后写入目标文件。</p> <h2 id=5-namenodesecondarynamenode>第5章 NameNode和SecondaryNameNode（重点）</h2> <h2 id=51-nn2nn>5.1 NN和2NN工作机制</h2> <p>思考：NameNode中的元数据是存储在哪里的？</p> <p>首先，我们做个假设，如果存储在NameNode节点的磁盘中，因为经常需要进行随机访问，还有响应客户请求，必然是效率过低。因此，元数据需要存放在内存中。但如果只存在内存中，一旦断电，元数据丢失，整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。</p> <p>这样又会带来新的问题，当在内存中的元数据更新时，如果同时更新FsImage，就会导致效率过低，但如果不更新，就会发生一致性问题，一旦NameNode节点断电，就会产生数据丢失。因此，引入Edits文件(只进行追加操作，效率很高)。每当元数据有更新或者添加元数据时，修改内存中的元数据并追加到Edits中。这样，一旦NameNode节点断电，可以通过FsImage和Edits的合并，合成元数据。</p> <p>但是，如果长时间添加数据到Edits中，会导致该文件数据过大，效率降低，而且一旦断电，恢复元数据需要的时间过长。因此，需要定期进行FsImage和Edits的合并，如果这个操作由NameNode节点完成，又会效率过低。因此，引入一个新的节点SecondaryNamenode，专门用于FsImage和Edits的合并。</p> <p>NN和2NN工作机制，如图3-14所示。</p> <p>图3-14 NN和2NN工作机制</p> <ol> <li>第一阶段：NameNode启动</li> </ol> <blockquote> <p>（1）第一次启动NameNode格式化后，创建Fsimage和Edits文件。如果不是第一次启动，直接加载编辑日志和镜像文件到内存。</p> <p>（2）客户端对元数据进行增删改的请求。</p> <p>（3）NameNode记录操作日志，更新滚动日志。</p> <p>（4）NameNode在内存中对数据进行增删改。</p> </blockquote> <ol> <li>第二阶段：Secondary NameNode工作</li> </ol> <p>（1）Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。</p> <p>（2）Secondary NameNode请求执行CheckPoint。</p> <p>（3）NameNode滚动正在写的Edits日志。</p> <p>（4）将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。</p> <p>（5）Secondary NameNode加载编辑日志和镜像文件到内存，并合并。</p> <p>（6）生成新的镜像文件fsimage.chkpoint。</p> <p>（7）拷贝fsimage.chkpoint到NameNode。</p> <p>（8）NameNode将fsimage.chkpoint重新命名成fsimage。</p> <table> <thead> <tr> <th><strong>NN和2NN工作机制详解：</strong> Fsimage：NameNode内存中元数据序列化后形成的文件。 Edits：记录客户端更新元数据信息的每一步操作（可通过Edits运算出元数据）。 NameNode启动时，先滚动Edits并生成一个空的edits.inprogress，然后加载Edits和Fsimage到内存中，此时NameNode内存就持有最新的元数据信息。Client开始对NameNode发送元数据的增删改的请求，这些请求的操作首先会被记录到edits.inprogress中（查询元数据的操作不会被记录在Edits中，因为查询操作不会更改元数据信息），如果此时NameNode挂掉，重启后会从Edits中读取元数据的信息。然后，NameNode会在内存中执行元数据的增删改的操作。 由于Edits中记录的操作会越来越多，Edits文件会越来越大，导致NameNode在启动加载Edits时会很慢，所以需要对Edits和Fsimage进行合并（所谓合并，就是将Edits和Fsimage加载到内存中，照着Edits中的操作一步步执行，最终形成新的Fsimage）。SecondaryNameNode的作用就是帮助NameNode进行Edits和Fsimage的合并工作。 SecondaryNameNode首先会询问NameNode是否需要CheckPoint（触发CheckPoint需要满足两个条件中的任意一个，定时时间到和Edits中数据写满了）。直接带回NameNode是否检查结果。SecondaryNameNode执行CheckPoint操作，首先会让NameNode滚动Edits并生成一个空的edits.inprogress，滚动Edits的目的是给Edits打个标记，以后所有新的操作都写入edits.inprogress，其他未合并的Edits和Fsimage会拷贝到SecondaryNameNode的本地，然后将拷贝的Edits和Fsimage加载到内存中进行合并，生成fsimage.chkpoint，然后将fsimage.chkpoint拷贝给NameNode，重命名为Fsimage后替换掉原来的Fsimage。NameNode在启动时就只需要加载之前未合并的Edits和Fsimage即可，因为合并过的Edits中的元数据信息已经被记录在Fsimage中。</th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <h2 id=52-fsimageedits>5.2 Fsimage和Edits解析</h2> <ol> <li> <p>概念</p> </li> <li> <p>oiv查看Fsimage文件</p> </li> </ol> <blockquote> <p>（1）查看oiv和oev命令</p> <p>[atguigu\@hadoop102 current]$ hdfs</p> <p><strong>oiv</strong> apply the offline fsimage viewer to an fsimage</p> <p><strong>oev</strong> apply the offline edits viewer to an edits file</p> <p>（2）基本语法</p> <p>hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径</p> <p>（3）案例实操</p> <p>[atguigu\@hadoop102 current]$ pwd</p> <p>/opt/module/hadoop-2.7.2/data/tmp/dfs/name/current</p> <p>[atguigu\@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-2.7.2/fsimage.xml</p> <p>[atguigu\@hadoop102 current]$ cat /opt/module/hadoop-2.7.2/fsimage.xml</p> <p>将显示的xml文件内容拷贝到Eclipse中创建的xml文件中，并格式化。部分显示结果如下。</p> <p>\&lt;inode></p> <p>\&lt;id>16386\&lt;/id></p> <p>\&lt;type>DIRECTORY\&lt;/type></p> <p>\&lt;name>user\&lt;/name></p> <p>\&lt;mtime>1512722284477\&lt;/mtime></p> <p>\&lt;permission>atguigu:supergroup:rwxr-xr-x\&lt;/permission></p> <p>\&lt;nsquota>-1\&lt;/nsquota></p> <p>\&lt;dsquota>-1\&lt;/dsquota></p> <p>\&lt;/inode></p> <p>\&lt;inode></p> <p>\&lt;id>16387\&lt;/id></p> <p>\&lt;type>DIRECTORY\&lt;/type></p> <p>\&lt;name>atguigu\&lt;/name></p> <p>\&lt;mtime>1512790549080\&lt;/mtime></p> <p>\&lt;permission>atguigu:supergroup:rwxr-xr-x\&lt;/permission></p> <p>\&lt;nsquota>-1\&lt;/nsquota></p> <p>\&lt;dsquota>-1\&lt;/dsquota></p> <p>\&lt;/inode></p> <p>\&lt;inode></p> <p>\&lt;id>16389\&lt;/id></p> <p>\&lt;type>FILE\&lt;/type></p> <p>\&lt;name>wc.input\&lt;/name></p> <p>\&lt;replication>3\&lt;/replication></p> <p>\&lt;mtime>1512722322219\&lt;/mtime></p> <p>\&lt;atime>1512722321610\&lt;/atime></p> <p>\&lt;perferredBlockSize>134217728\&lt;/perferredBlockSize></p> <p>\&lt;permission>atguigu:supergroup:rw-r&ndash;r&ndash;\&lt;/permission></p> <p>\&lt;blocks></p> <p>\&lt;block></p> <p>\&lt;id>1073741825\&lt;/id></p> <p>\&lt;genstamp>1001\&lt;/genstamp></p> <p>\&lt;numBytes>59\&lt;/numBytes></p> <p>\&lt;/block></p> <p>\&lt;/blocks></p> <p>\&lt;/inode ></p> <p>思考：可以看出，Fsimage中没有记录块所对应DataNode，为什么？</p> <p>在集群启动后，要求DataNode上报数据块信息，并间隔一段时间后再次上报。</p> </blockquote> <ol> <li>oev查看Edits文件</li> </ol> <blockquote> <p>（1）基本语法</p> <p>hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径</p> <p>（2）案例实操</p> <p>[atguigu\@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-2.7.2/edits.xml</p> <p>[atguigu\@hadoop102 current]$ cat /opt/module/hadoop-2.7.2/edits.xml</p> <p>将显示的xml文件内容拷贝到Eclipse中创建的xml文件中，并格式化。显示结果如下。</p> <p>\&lt;?xml version=&rdquo;1.0&rdquo; encoding=&rdquo;UTF-8&rdquo;?></p> <p>\&lt;EDITS></p> <p>\&lt;EDITS_VERSION>-63\&lt;/EDITS_VERSION></p> <p>\&lt;RECORD></p> <p>\&lt;OPCODE>OP_START_LOG_SEGMENT\&lt;/OPCODE></p> <p>\&lt;DATA></p> <p>\&lt;TXID>129\&lt;/TXID></p> <p>\&lt;/DATA></p> <p>\&lt;/RECORD></p> <p>\&lt;RECORD></p> <p>\&lt;OPCODE>OP_ADD\&lt;/OPCODE></p> <p>\&lt;DATA></p> <p>\&lt;TXID>130\&lt;/TXID></p> <p>\&lt;LENGTH>0\&lt;/LENGTH></p> <p>\&lt;INODEID>16407\&lt;/INODEID></p> <p>\&lt;PATH>/hello7.txt\&lt;/PATH></p> <p>\&lt;REPLICATION>2\&lt;/REPLICATION></p> <p>\&lt;MTIME>1512943607866\&lt;/MTIME></p> <p>\&lt;ATIME>1512943607866\&lt;/ATIME></p> <p>\&lt;BLOCKSIZE>134217728\&lt;/BLOCKSIZE></p> <p>\&lt;CLIENT_NAME>DFSClient_NONMAPREDUCE_-1544295051_1\&lt;/CLIENT_NAME></p> <p>\&lt;CLIENT_MACHINE>192.168.1.5\&lt;/CLIENT_MACHINE></p> <p>\&lt;OVERWRITE>true\&lt;/OVERWRITE></p> <p>\&lt;PERMISSION_STATUS></p> <p>\&lt;USERNAME>atguigu\&lt;/USERNAME></p> <p>\&lt;GROUPNAME>supergroup\&lt;/GROUPNAME></p> <p>\&lt;MODE>420\&lt;/MODE></p> <p>\&lt;/PERMISSION_STATUS></p> <p>\&lt;RPC_CLIENTID>908eafd4-9aec-4288-96f1-e8011d181561\&lt;/RPC_CLIENTID></p> <p>\&lt;RPC_CALLID>0\&lt;/RPC_CALLID></p> <p>\&lt;/DATA></p> <p>\&lt;/RECORD></p> <p>\&lt;RECORD></p> <p>\&lt;OPCODE>OP_ALLOCATE_BLOCK_ID\&lt;/OPCODE></p> <p>\&lt;DATA></p> <p>\&lt;TXID>131\&lt;/TXID></p> <p>\&lt;BLOCK_ID>1073741839\&lt;/BLOCK_ID></p> <p>\&lt;/DATA></p> <p>\&lt;/RECORD></p> <p>\&lt;RECORD></p> <p>\&lt;OPCODE>OP_SET_GENSTAMP_V2\&lt;/OPCODE></p> <p>\&lt;DATA></p> <p>\&lt;TXID>132\&lt;/TXID></p> <p>\&lt;GENSTAMPV2>1016\&lt;/GENSTAMPV2></p> <p>\&lt;/DATA></p> <p>\&lt;/RECORD></p> <p>\&lt;RECORD></p> <p>\&lt;OPCODE>OP_ADD_BLOCK\&lt;/OPCODE></p> <p>\&lt;DATA></p> <p>\&lt;TXID>133\&lt;/TXID></p> <p>\&lt;PATH>/hello7.txt\&lt;/PATH></p> <p>\&lt;BLOCK></p> <p>\&lt;BLOCK_ID>1073741839\&lt;/BLOCK_ID></p> <p>\&lt;NUM_BYTES>0\&lt;/NUM_BYTES></p> <p>\&lt;GENSTAMP>1016\&lt;/GENSTAMP></p> <p>\&lt;/BLOCK></p> <p>\&lt;RPC_CLIENTID>\&lt;/RPC_CLIENTID></p> <p>\&lt;RPC_CALLID>-2\&lt;/RPC_CALLID></p> <p>\&lt;/DATA></p> <p>\&lt;/RECORD></p> <p>\&lt;RECORD></p> <p>\&lt;OPCODE>OP_CLOSE\&lt;/OPCODE></p> <p>\&lt;DATA></p> <p>\&lt;TXID>134\&lt;/TXID></p> <p>\&lt;LENGTH>0\&lt;/LENGTH></p> <p>\&lt;INODEID>0\&lt;/INODEID></p> <p>\&lt;PATH>/hello7.txt\&lt;/PATH></p> <p>\&lt;REPLICATION>2\&lt;/REPLICATION></p> <p>\&lt;MTIME>1512943608761\&lt;/MTIME></p> <p>\&lt;ATIME>1512943607866\&lt;/ATIME></p> <p>\&lt;BLOCKSIZE>134217728\&lt;/BLOCKSIZE></p> <p>\&lt;CLIENT_NAME>\&lt;/CLIENT_NAME></p> <p>\&lt;CLIENT_MACHINE>\&lt;/CLIENT_MACHINE></p> <p>\&lt;OVERWRITE>false\&lt;/OVERWRITE></p> <p>\&lt;BLOCK></p> <p>\&lt;BLOCK_ID>1073741839\&lt;/BLOCK_ID></p> <p>\&lt;NUM_BYTES>25\&lt;/NUM_BYTES></p> <p>\&lt;GENSTAMP>1016\&lt;/GENSTAMP></p> <p>\&lt;/BLOCK></p> <p>\&lt;PERMISSION_STATUS></p> <p>\&lt;USERNAME>atguigu\&lt;/USERNAME></p> <p>\&lt;GROUPNAME>supergroup\&lt;/GROUPNAME></p> <p>\&lt;MODE>420\&lt;/MODE></p> <p>\&lt;/PERMISSION_STATUS></p> <p>\&lt;/DATA></p> <p>\&lt;/RECORD></p> <p>\&lt;/EDITS ></p> <p>思考：NameNode如何确定下次开机启动的时候合并哪些Edits？</p> </blockquote> <h2 id=53-checkpoint>5.3 CheckPoint时间设置</h2> <p>（1）通常情况下，SecondaryNameNode每隔一小时执行一次。</p> <p>[hdfs-default.xml]</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.checkpoint.period\&lt;/name></p> <p>\&lt;value>3600\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <p>（2）一分钟检查一次操作次数，3当操作次数达到1百万时，SecondaryNameNode执行一次。</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.checkpoint.txns\&lt;/name></p> <p>\&lt;value>1000000\&lt;/value></p> <p>\&lt;description>操作动作次数\&lt;/description></p> <p>\&lt;/property></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.checkpoint.check.period\&lt;/name></p> <p>\&lt;value>60\&lt;/value></p> <p>\&lt;description> 1分钟检查一次操作次数\&lt;/description></p> <p>\&lt;/property ></p> </blockquote> <h2 id=54-namenode>5.4 NameNode故障处理</h2> <p>NameNode故障后，可以采用如下两种方法恢复数据。</p> <p><strong>方法一：将SecondaryNameNode中数据拷贝到NameNode存储数据的目录；</strong></p> <ol> <li> <p>kill -9 NameNode进程</p> </li> <li> <p>删除NameNode存储的数据（/opt/module/hadoop-2.7.2/data/tmp/dfs/name）</p> </li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*</p> </blockquote> <ol> <li>拷贝SecondaryNameNode中数据到原NameNode存储数据目录</li> </ol> <blockquote> <p>[atguigu\@hadoop102 dfs]$ scp -r atguigu\@hadoop104:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary/* ./name/</p> </blockquote> <ol> <li>重新启动NameNode</li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ sbin/hadoop-daemon.sh start namenode</p> </blockquote> <p><strong>方法二：使用-importCheckpoint选项启动NameNode守护进程，从而将SecondaryNameNode中数据拷贝到NameNode目录中。</strong></p> <ol> <li>修改hdfs-site.xml中的</li> </ol> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.checkpoint.period\&lt;/name></p> <p>\&lt;value>120\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.name.dir\&lt;/name></p> <p>\&lt;value>/opt/module/hadoop-2.7.2/data/tmp/dfs/name\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <ol> <li> <p>kill -9 NameNode进程</p> </li> <li> <p>删除NameNode存储的数据（/opt/module/hadoop-2.7.2/data/tmp/dfs/name）</p> </li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*</p> </blockquote> <p>4. 如果SecondaryNameNode不和NameNode在一个主机节点上，需要将SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录，并删除in_use.lock文件</p> <blockquote> <p>[atguigu\@hadoop102 dfs]$ scp -r atguigu\@hadoop104:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary ./</p> <p>[atguigu\@hadoop102 namesecondary]$ rm -rf in_use.lock</p> <p>[atguigu\@hadoop102 dfs]$ pwd</p> <p>/opt/module/hadoop-2.7.2/data/tmp/dfs</p> <p>[atguigu\@hadoop102 dfs]$ ls</p> <p>data name namesecondary</p> </blockquote> <ol> <li>导入检查点数据（等待一会ctrl+c结束掉）</li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hdfs namenode -importCheckpoint</p> </blockquote> <ol> <li>启动NameNode</li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ sbin/hadoop-daemon.sh start namenode</p> </blockquote> <h2 id=55>5.5 集群安全模式</h2> <ol> <li> <p>概述</p> </li> <li> <p>基本语法</p> </li> </ol> <p>集群处于安全模式，不能执行重要操作（写操作）。集群启动完成后，自动退出安全模式。</p> <p>（1）bin/hdfs dfsadmin -safemode get （功能描述：查看安全模式状态）</p> <p>（2）bin/hdfs dfsadmin -safemode enter （功能描述：进入安全模式状态）</p> <p>（3）bin/hdfs dfsadmin -safemode leave （功能描述：离开安全模式状态）</p> <p>（4）bin/hdfs dfsadmin -safemode wait （功能描述：等待安全模式状态）</p> <ol> <li>案例</li> </ol> <p>模拟等待安全模式</p> <p>（1）查看当前模式</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -safemode get</p> <p>Safe mode is OFF</p> </blockquote> <p>（2）先进入安全模式</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hdfs dfsadmin -safemode enter</p> </blockquote> <p>（3）创建并执行下面的脚本</p> <blockquote> <p>在/opt/module/hadoop-2.7.2路径上，编辑一个脚本safemode.sh</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ touch safemode.sh</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ vim safemode.sh</p> <p>#!/bin/bash</p> <p>hdfs dfsadmin -safemode wait</p> <p>hdfs dfs -put /opt/module/hadoop-2.7.2/README.txt /</p> <p>执行脚本</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ chmod 777 safemode.sh</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ ./safemode.sh</p> </blockquote> <p>（4）再打开一个窗口，执行</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hdfs dfsadmin -safemode leave</p> </blockquote> <p>（5）观察</p> <blockquote> <p>（a）再观察上一个窗口</p> <p>Safe mode is OFF</p> <p>（b）HDFS集群上已经有上传的数据了。</p> </blockquote> <h2 id=56-namenode>5.6 NameNode多目录配置</h2> <ol> <li> <p>NameNode的本地目录可以配置成多个，且每个目录存放内容相同，增加了可靠性</p> </li> <li> <p>具体配置如下</p> </li> </ol> <p>（1）在hdfs-site.xml文件中增加如下内容</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.name.dir\&lt;/name></p> <p>\&lt;value>></p> <p>\&lt;/property></p> </blockquote> <p>（2）停止集群，删除data和logs中所有数据。</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ rm -rf data/ logs/</p> <p>[atguigu\@hadoop103 hadoop-2.7.2]$ rm -rf data/ logs/</p> <p>[atguigu\@hadoop104 hadoop-2.7.2]$ rm -rf data/ logs/</p> </blockquote> <p>（3）格式化集群并启动。</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hdfs namenode –format</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh</p> </blockquote> <p>（4）查看结果</p> <blockquote> <p>[atguigu\@hadoop102 dfs]$ ll</p> <p>总用量 12</p> <p>drwx------. 3 atguigu atguigu 4096 12月 11 08:03 data</p> <p>drwxrwxr-x. 3 atguigu atguigu 4096 12月 11 08:03 name1</p> <p>drwxrwxr-x. 3 atguigu atguigu 4096 12月 11 08:03 name2</p> </blockquote> <h2 id=6-datanode>第6章 DataNode</h2> <h2 id=61-datanode>6.1 DataNode工作机制</h2> <p>DataNode工作机制，如图3-15所示。</p> <p>图3-15 DataNode工作机制</p> <p>1）一个数据块在DataNode上以文件形式存储在磁盘上，包括两个文件，一个是数据本身，一个是元数据包括数据块的长度，块数据的校验和，以及时间戳。</p> <p>2）DataNode启动后向NameNode注册，通过后，周期性（1小时）的向NameNode上报所有的块信息。</p> <p>3）心跳是每3秒一次，心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器，或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳，则认为该节点不可用。</p> <p>4）集群运行中可以安全加入和退出一些机器。</p> <h2 id=62>6.2 数据完整性</h2> <p>思考：如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号（1）和绿灯信号（0），但是存储该数据的磁盘坏了，一直显示是绿灯，是否很危险？同理DataNode节点上的数据损坏了，却没有发现，是否也很危险，那么如何解决呢？</p> <p>如下是DataNode节点保证数据完整性的方法。</p> <p>1）当DataNode读取Block的时候，它会计算CheckSum。</p> <p>2）如果计算后的CheckSum，与Block创建时值不一样，说明Block已经损坏。</p> <p>3）Client读取其他DataNode上的Block。</p> <p>4）DataNode在其文件创建后周期验证CheckSum，如图3-16所示。</p> <p>图3-16 校验和</p> <h2 id=63>6.3 掉线时限参数设置</h2> <p>需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒，dfs.heartbeat.interval的单位为秒。</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.heartbeat.recheck-interval\&lt;/name></p> <p>\&lt;value>300000\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;property></p> <p>\&lt;name>dfs.heartbeat.interval\&lt;/name></p> <p>\&lt;value>3\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <h2 id=64>6.4 服役新数据节点</h2> <ol> <li>需求</li> </ol> <p>随着公司业务的增长，数据量越来越大，原有的数据节点的容量已经不能满足存储数据的需求，需要在原有集群基础上动态添加新的数据节点。</p> <ol> <li>环境准备</li> </ol> <p>（1）在hadoop104主机上再克隆一台hadoop105主机</p> <p>（2）修改IP地址和主机名称</p> <p>（3）<strong>删除原来HDFS文件系统留存的文件（/opt/module/hadoop-2.7.2/data和log）</strong></p> <p>（4）source一下配置文件</p> <blockquote> <p>[atguigu\@hadoop105 hadoop-2.7.2]$ source /etc/profile</p> </blockquote> <ol> <li>服役新节点具体步骤</li> </ol> <p>（1）直接启动DataNode，即可关联到集群</p> <blockquote> <p>[atguigu\@hadoop105 hadoop-2.7.2]$ sbin/hadoop-daemon.sh start datanode</p> <p>[atguigu\@hadoop105 hadoop-2.7.2]$ sbin/yarn-daemon.sh start nodemanager</p> </blockquote> <p><img alt src=33bbf8b5ea1b3296d5f934659de512ca.png></p> <p>（2）在hadoop105上上传文件</p> <blockquote> <p>[atguigu\@hadoop105 hadoop-2.7.2]$ hadoop fs -put /opt/module/hadoop-2.7.2/LICENSE.txt /</p> </blockquote> <p>（3）如果数据不均衡，可以用命令实现集群的再平衡</p> <blockquote> <p>[atguigu\@hadoop102 sbin]$ ./start-balancer.sh</p> <p>starting balancer, logging to /opt/module/hadoop-2.7.2/logs/hadoop-atguigu-balancer-hadoop102.out</p> <p>Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved</p> </blockquote> <h2 id=65>6.5 退役旧数据节点</h2> <h3 id=651>6.5.1 添加白名单</h3> <p>添加到白名单的主机节点，都允许访问NameNode，不在白名单的主机节点，都会被退出。</p> <p>配置白名单的具体步骤如下：</p> <p>（1）在NameNode的/opt/module/hadoop-2.7.2/etc/hadoop目录下创建dfs.hosts文件</p> <blockquote> <p>[atguigu\@hadoop102 hadoop]$ pwd</p> <p>/opt/module/hadoop-2.7.2/etc/hadoop</p> <p>[atguigu\@hadoop102 hadoop]$ touch dfs.hosts</p> <p>[atguigu\@hadoop102 hadoop]$ vi dfs.hosts</p> <p>添加如下主机名称（不添加hadoop105）</p> <p>hadoop102</p> <p>hadoop103</p> <p>hadoop104</p> </blockquote> <p>（2）在NameNode的hdfs-site.xml配置文件中增加dfs.hosts属性</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.hosts\&lt;/name></p> <p>\&lt;value>/opt/module/hadoop-2.7.2/etc/hadoop/dfs.hosts\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <p>（3）配置文件分发</p> <blockquote> <p>[atguigu\@hadoop102 hadoop]$ xsync hdfs-site.xml</p> </blockquote> <p>（4）刷新NameNode</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -refreshNodes</p> </blockquote> <p>Refresh nodes successful</p> <p>（5）更新ResourceManager节点</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ yarn rmadmin -refreshNodes</p> <p>17/06/24 14:17:11 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.1.103:8033</p> </blockquote> <p>（6）在web浏览器上查看</p> <p><img alt src=77cf47ec5e2afc321c255408876a778d.png></p> <ol> <li>如果数据不均衡，可以用命令实现集群的再平衡</li> </ol> <blockquote> <p>[atguigu\@hadoop102 sbin]$ ./start-balancer.sh</p> <p>starting balancer, logging to /opt/module/hadoop-2.7.2/logs/hadoop-atguigu-balancer-hadoop102.out</p> <p>Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved</p> </blockquote> <h3 id=652>6.5.2 黑名单退役</h3> <p>在黑名单上面的主机都会被强制退出。</p> <p>1.在NameNode的/opt/module/hadoop-2.7.2/etc/hadoop目录下创建dfs.hosts.exclude文件</p> <blockquote> <p>[atguigu\@hadoop102 hadoop]$ pwd</p> <p>/opt/module/hadoop-2.7.2/etc/hadoop</p> <p>[atguigu\@hadoop102 hadoop]$ touch dfs.hosts.exclude</p> <p>[atguigu\@hadoop102 hadoop]$ vi dfs.hosts.exclude</p> </blockquote> <p>添加如下主机名称（要退役的节点）</p> <blockquote> <p>hadoop105</p> </blockquote> <p>2．在NameNode的hdfs-site.xml配置文件中增加dfs.hosts.exclude属性</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.hosts.exclude\&lt;/name></p> <p>\&lt;value>/opt/module/hadoop-2.7.2/etc/hadoop/dfs.hosts.exclude\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <p>3．刷新NameNode、刷新ResourceManager</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -refreshNodes</p> <p>Refresh nodes successful</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ yarn rmadmin -refreshNodes</p> <p>17/06/24 14:55:56 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.1.103:8033</p> <ol> <li>检查Web浏览器，退役节点的状态为decommission in progress（退役中），说明数据节点正在复制块到其他节点，如图3-17所示</li> </ol> </blockquote> <p><img alt src=67fd75f603c6e7da049699bb529ef897.png></p> <p>图3-17 退役中</p> <blockquote> <p>5. 等待退役节点状态为decommissioned（所有块已经复制完成），停止该节点及节点资源管理器。注意：如果副本数是3，服役的节点小于等于3，是不能退役成功的，需要修改副本数后才能退役，如图3-18所示</p> </blockquote> <p><img alt src=b33a1415c759368a1e9a694e2ec10372.png></p> <p>图3-18 已退役</p> <blockquote> <p>[atguigu\@hadoop105 hadoop-2.7.2]$ sbin/hadoop-daemon.sh stop datanode</p> <p>stopping datanode</p> <p>[atguigu\@hadoop105 hadoop-2.7.2]$ sbin/yarn-daemon.sh stop nodemanager</p> <p>stopping nodemanager</p> </blockquote> <ol> <li>如果数据不均衡，可以用命令实现集群的再平衡</li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ sbin/start-balancer.sh</p> <p>starting balancer, logging to /opt/module/hadoop-2.7.2/logs/hadoop-atguigu-balancer-hadoop102.out</p> <p>Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved</p> </blockquote> <p>注意：不允许白名单和黑名单中同时出现同一个主机名称。</p> <h2 id=66-datanode>6.6 Datanode多目录配置</h2> <blockquote> <ol> <li>DataNode也可以配置成多个目录，每个目录存储的数据不一样。即：数据不是副本</li> </ol> </blockquote> <p>2．具体配置如下</p> <p>hdfs-site.xml</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.datanode.data.dir\&lt;/name></p> <p>\&lt;value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <h2 id=7-hdfs-2x>第7章 HDFS 2.X新特性</h2> <h2 id=71>7.1 集群间数据拷贝</h2> <p>1．scp实现两个远程主机之间的文件复制</p> <p>scp -r hello.txt root\@hadoop103:/user/atguigu/hello.txt](root@hadoop103:/user/atguigu/hello.txt) // 推 push</p> <p>scp -r root\@hadoop103:/user/atguigu/hello.txt hello.txt](mailto:root@hadoop103:/user/atguigu/hello.txt%20%20hello.txt) // 拉 pull</p> <p>scp -r root\@hadoop103:/user/atguigu/hello.txt](root@hadoop103:/user/atguigu/hello.txt) root\@hadoop104:/user/atguigu //是通过本地主机中转实现两个远程主机的文件复制；如果在两个远程主机之间ssh没有配置的情况下可以使用该方式。</p> <p>2．采用distcp命令实现两个Hadoop集群之间的递归数据复制</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hadoop distcp</p> <p>hdfs://haoop102:9000/user/atguigu/hello.txt hdfs://hadoop103:9000/user/atguigu/hello.txt</p> </blockquote> <h2 id=72>7.2 小文件存档</h2> <p>3．案例实操</p> <blockquote> <p>（1）需要启动YARN进程</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ start-yarn.sh</p> <p>（2）归档文件</p> <p>把/user/atguigu/input目录里面的所有文件归档成一个叫input.har的归档文件，并把归档后文件存储到/user/atguigu/output路径下。</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ bin/hadoop archive -archiveName input.har –p /user/atguigu/input /user/atguigu/output</p> <p>（3）查看归档</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr /user/atguigu/output/input.har</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr har:///user/atguigu/output/input.har</p> <p>（4）解归档文件</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -cp har:/// user/atguigu/output/input.har/* /user/atguigu</p> </blockquote> <h2 id=73>7.3 回收站</h2> <p>开启回收站功能，可以将删除的文件在不超时的情况下，恢复原数据，起到防止误删除、备份等作用。</p> <p>1．回收站参数设置及工作机制</p> <p>图3-19 回收站</p> <p>2．启用回收站</p> <p>修改core-site.xml，配置垃圾回收时间为1分钟。</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>fs.trash.interval\&lt;/name></p> <p>\&lt;value>1\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <p>3．查看回收站</p> <p>回收站在集群中的路径：/user/atguigu/.Trash/….</p> <p>4．修改访问垃圾回收站用户名称</p> <p>进入垃圾回收站用户名称，默认是dr.who，修改为atguigu用户</p> <p>[core-site.xml]</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>hadoop.http.staticuser.user\&lt;/name></p> <p>\&lt;value>atguigu\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <ol> <li>通过程序删除的文件不会经过回收站，需要调用moveToTrash()才进入回收站</li> </ol> <blockquote> <p>Trash trash = New Trash(conf);</p> <p>trash.moveToTrash(path);</p> </blockquote> <ol> <li>恢复回收站数据</li> </ol> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -mv</p> <p>/user/atguigu/.Trash/Current/user/atguigu/input /user/atguigu/input</p> <ol> <li>清空回收站</li> </ol> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hadoop fs -expunge</p> </blockquote> <h2 id=74>7.4 快照管理</h2> <p>2．案例实操</p> <p>（1）开启/禁用指定目录的快照功能</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -allowSnapshot /user/atguigu/input</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -disallowSnapshot /user/atguigu/input</p> </blockquote> <p>（2）对目录创建快照</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfs -createSnapshot /user/atguigu/input</p> <p>通过web访问hdfs://hadoop102:50070/user/atguigu/input/.snapshot/s…..// 快照和源文件使用相同数据</p> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfs -lsr /user/atguigu/input/.snapshot/</p> </blockquote> <p>（3）指定名称创建快照</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfs -createSnapshot /user/atguigu/input miao170508</p> </blockquote> <p>（4）重命名快照</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfs -renameSnapshot /user/atguigu/input/ miao170508 atguigu170508</p> </blockquote> <p>（5）列出当前用户所有可快照目录</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs lsSnapshottableDir</p> </blockquote> <p>（6）比较两个快照目录的不同之处</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs snapshotDiff</p> <p>/user/atguigu/input/ . .snapshot/atguigu170508</p> </blockquote> <p>（7）恢复快照</p> <blockquote> <p>[atguigu\@hadoop102 hadoop-2.7.2]$ hdfs dfs -cp</p> <p>/user/atguigu/input/.snapshot/s20170708-134303.027 /user</p> </blockquote> <h2 id=8-hdfs-ha>第8章 HDFS HA高可用</h2> <h2 id=81-ha>8.1 HA概述</h2> <p>1）所谓HA（High Available），即高可用（7*24小时不中断服务）。</p> <p>2）实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制：HDFS的HA和YARN的HA。</p> <p>3）Hadoop2.0之前，在HDFS集群中NameNode存在单点故障（SPOF）。</p> <p>4）NameNode主要在以下两个方面影响HDFS集群</p> <p>NameNode机器发生意外，如宕机，集群将无法使用，直到管理员重启</p> <p>NameNode机器需要升级，包括软件、硬件升级，此时集群也将无法使用</p> <p>HDFS HA功能通过配置Active/Standby两个NameNodes实现在集群中对NameNode的热备来解决上述问题。如果出现故障，如机器崩溃或机器需要升级维护，这时可通过此种方式将NameNode很快的切换到另外一台机器。</p> <h2 id=82-hdfs-ha>8.2 HDFS-HA工作机制</h2> <p>通过双NameNode消除单点故障</p> <h3 id=821-hdfs-ha>8.2.1 HDFS-HA工作要点</h3> <ol> <li>元数据管理方式需要改变</li> </ol> <p>内存中各自保存一份元数据；</p> <p>Edits日志只有Active状态的NameNode节点可以做写操作；</p> <p>两个NameNode都可以读取Edits；</p> <p>共享的Edits放在一个共享存储中管理（qjournal和NFS两个主流实现）；</p> <ol> <li>需要一个状态管理功能模块</li> </ol> <p>实现了一个zkfailover，常驻在每一个namenode所在的节点，每一个zkfailover负责监控自己所在NameNode节点，利用zk进行状态标识，当需要进行状态切换时，由zkfailover来负责切换，切换时需要防止brain split现象的发生。</p> <ol> <li> <p>必须保证两个NameNode之间能够ssh无密码登录</p> </li> <li> <p>隔离（Fence），即同一时刻仅仅有一个NameNode对外提供服务</p> </li> </ol> <h3 id=822-hdfs-ha>8.2.2 HDFS-HA自动故障转移工作机制</h3> <p>前面学习了使用命令hdfs haadmin -failover手动进行故障转移，在该模式下，即使现役NameNode已经失效，系统也不会自动从现役NameNode转移到待机NameNode，下面学习如何配置部署HA自动进行故障转移。自动故障转移为HDFS部署增加了两个新组件：ZooKeeper和ZKFailoverController（ZKFC）进程，如图3-20所示。ZooKeeper是维护少量协调数据，通知客户端这些数据的改变和监视客户端故障的高可用服务。HA的自动故障转移依赖于ZooKeeper的以下功能：</p> <p>**1）故障检测：**集群中的每个NameNode在ZooKeeper中维护了一个持久会话，如果机器崩溃，ZooKeeper中的会话将终止，ZooKeeper通知另一个NameNode需要触发故障转移。</p> <p>**2）现役NameNode选择：**ZooKeeper提供了一个简单的机制用于唯一的选择一个节点为active状态。如果目前现役NameNode崩溃，另一个节点可能从ZooKeeper获得特殊的排外锁以表明它应该成为现役NameNode。</p> <p>ZKFC是自动故障转移中的另一个新组件，是ZooKeeper的客户端，也监视和管理NameNode的状态。每个运行NameNode的主机也运行了一个ZKFC进程，ZKFC负责：</p> <p>**1）健康监测：**ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode，只要该NameNode及时地回复健康状态，ZKFC认为该节点是健康的。如果该节点崩溃，冻结或进入不健康状态，健康监测器标识该节点为非健康的。</p> <p>**2）ZooKeeper会话管理：**当本地NameNode是健康的，ZKFC保持一个在ZooKeeper中打开的会话。如果本地NameNode处于active状态，ZKFC也保持一个特殊的znode锁，该锁使用了ZooKeeper对短暂节点的支持，如果会话终止，锁节点将自动删除。</p> <p>**3）基于ZooKeeper的选择：**如果本地NameNode是健康的，且ZKFC发现没有其它的节点当前持有znode锁，它将为自己获取该锁。如果成功，则它已经赢得了选择，并负责运行故障转移进程以使它的本地NameNode为Active。故障转移进程与前面描述的手动故障转移相似，首先如果必要保护之前的现役NameNode，然后本地NameNode转换为Active状态。</p> <p>图3-20 HDFS-HA故障转移机制</p> <h2 id=83-hdfs-ha>8.3 HDFS-HA集群配置</h2> <h3 id=831>8.3.1 环境准备</h3> <ol> <li> <p>修改IP</p> </li> <li> <p>修改主机名及主机名和IP地址的映射</p> </li> <li> <p>关闭防火墙</p> </li> <li> <p>ssh免密登录</p> </li> <li> <p>安装JDK，配置环境变量等</p> </li> </ol> <h3 id=832>8.3.2 规划集群</h3> <p>表3-1</p> <table> <thead> <tr> <th>hadoop102</th> <th>hadoop103</th> <th>hadoop104</th> </tr> </thead> <tbody> <tr> <td>NameNode</td> <td>NameNode</td> <td></td> </tr> <tr> <td>JournalNode</td> <td>JournalNode</td> <td>JournalNode</td> </tr> <tr> <td>DataNode</td> <td>DataNode</td> <td>DataNode</td> </tr> <tr> <td>ZK</td> <td>ZK</td> <td>ZK</td> </tr> <tr> <td></td> <td>ResourceManager</td> <td></td> </tr> <tr> <td>NodeManager</td> <td>NodeManager</td> <td>NodeManager</td> </tr> </tbody> </table> <h3 id=833-zookeeper>8.3.3 配置Zookeeper集群</h3> <ol> <li>集群规划</li> </ol> <p>在hadoop102、hadoop103和hadoop104三个节点上部署Zookeeper。</p> <ol> <li>解压安装</li> </ol> <blockquote> <p>（1）解压Zookeeper安装包到/opt/module/目录下</p> <p>[atguigu\@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/</p> <p>（2）在/opt/module/zookeeper-3.4.10/这个目录下创建zkData</p> <p>mkdir -p zkData</p> <p>（3）重命名/opt/module/zookeeper-3.4.10/conf这个目录下的zoo_sample.cfg为zoo.cfg</p> <p>mv zoo_sample.cfg zoo.cfg</p> </blockquote> <ol> <li>配置zoo.cfg文件</li> </ol> <p>（1）具体配置</p> <blockquote> <p>dataDir=/opt/module/zookeeper-3.4.10/zkData</p> </blockquote> <p>增加如下配置</p> <blockquote> <p>#######################cluster##########################</p> <p>server.2=hadoop102:2888:3888</p> <p>server.3=hadoop103:2888:3888</p> <p>server.4=hadoop104:2888:3888</p> </blockquote> <p>（2）配置参数解读</p> <p>Server.A=B:C:D。</p> <p>A是一个数字，表示这个是第几号服务器；</p> <p>B是这个服务器的IP地址；</p> <p>C是这个服务器与集群中的Leader服务器交换信息的端口；</p> <p>D是万一集群中的Leader服务器挂了，需要一个端口来重新进行选举，选出一个新的Leader，而这个端口就是用来执行选举时服务器相互通信的端口。</p> <p>集群模式下配置一个文件myid，这个文件在dataDir目录下，这个文件里面有一个数据就是A的值，Zookeeper启动时读取此文件，拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。</p> <ol> <li>集群操作</li> </ol> <blockquote> <p>（1）在/opt/module/zookeeper-3.4.10/zkData目录下创建一个myid的文件</p> <p>touch myid</p> <p>添加myid文件，注意一定要在linux里面创建，在notepad++里面很可能乱码</p> <p>（2）编辑myid文件</p> <p>vi myid</p> <p>在文件中添加与server对应的编号：如2</p> <p>（3）拷贝配置好的zookeeper到其他机器上</p> <p>scp -r zookeeper-3.4.10/<a href></a> root\@hadoop103.atguigu.com:/opt/app/</p> <p>scp -r zookeeper-3.4.10/ root\@hadoop104.atguigu.com:/opt/app/</p> <p>并分别修改myid文件中内容为3、4</p> <p>（4）分别启动zookeeper</p> <p>[root\@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh start</p> <p>[root\@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh start</p> <p>[root\@hadoop104 zookeeper-3.4.10]# bin/zkServer.sh start</p> <p>（5）查看状态</p> <p>[root\@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh status</p> <p>JMX enabled by default</p> <p>Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg</p> <p>Mode: follower</p> <p>[root\@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh status</p> <p>JMX enabled by default</p> <p>Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg</p> <p>Mode: leader</p> <p>[root\@hadoop104 zookeeper-3.4.5]# bin/zkServer.sh status</p> <p>JMX enabled by default</p> <p>Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg</p> <p>Mode: follower</p> </blockquote> <h3 id=834-hdfs-ha>8.3.4 配置HDFS-HA集群</h3> <ol> <li> <p>官方地址：<a href=http://hadoop.apache.org/ >http://hadoop.apache.org/</a></p> </li> <li> <p>在opt目录下创建一个ha文件夹</p> </li> </ol> <blockquote> <p>mkdir ha</p> </blockquote> <ol> <li>将/opt/app/下的 hadoop-2.7.2拷贝到/opt/ha目录下</li> </ol> <blockquote> <p>cp -r hadoop-2.7.2/ /opt/ha/</p> </blockquote> <ol> <li>配置hadoop-env.sh</li> </ol> <table> <thead> <tr> <th>export JAVA_HOME=/opt/module/jdk1.8.0_144</th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <ol> <li>配置core-site.xml</li> </ol> <table> <thead> <tr> <th>\&lt;configuration></th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <blockquote> <p>\&lt;!&ndash; 把两个NameNode）的地址组装成一个集群mycluster &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>fs.defaultFS\&lt;/name></p> <p>\&lt;value>hdfs://mycluster\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 指定hadoop运行时产生文件的存储目录 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>hadoop.tmp.dir\&lt;/name></p> <p>\&lt;value>/opt/ha/hadoop-2.7.2/data/tmp\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;/configuration></p> </blockquote> <ol> <li>配置hdfs-site.xml</li> </ol> <table> <thead> <tr> <th>\&lt;configuration></th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <blockquote> <p>\&lt;!&ndash; 完全分布式集群名称 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.nameservices\&lt;/name></p> <p>\&lt;value>mycluster\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 集群中NameNode节点都有哪些 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.ha.namenodes.mycluster\&lt;/name></p> <p>\&lt;value>nn1,nn2\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; nn1的RPC通信地址 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.rpc-address.mycluster.nn1\&lt;/name></p> <p>\&lt;value>hadoop102:9000\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; nn2的RPC通信地址 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.rpc-address.mycluster.nn2\&lt;/name></p> <p>\&lt;value>hadoop103:9000\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; nn1的http通信地址 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.http-address.mycluster.nn1\&lt;/name></p> <p>\&lt;value>hadoop102:50070\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; nn2的http通信地址 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.http-address.mycluster.nn2\&lt;/name></p> <p>\&lt;value>hadoop103:50070\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 指定NameNode元数据在JournalNode上的存放位置 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.namenode.shared.edits.dir\&lt;/name></p> <p>\&lt;value>qjournal://hadoop102:8485;hadoop103:8485;hadoop104:8485/mycluster\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 配置隔离机制，即同一时刻只能有一台服务器对外响应 &ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.ha.fencing.methods\&lt;/name></p> <p>\&lt;value>sshfence\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 使用隔离机制时需要ssh无秘钥登录&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.ha.fencing.ssh.private-key-files\&lt;/name></p> <p>\&lt;value>/home/atguigu/.ssh/id_rsa\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 声明journalnode服务器存储目录&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.journalnode.edits.dir\&lt;/name></p> <p>\&lt;value>/opt/ha/hadoop-2.7.2/data/jn\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 关闭权限检查&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.permissions.enable\&lt;/name></p> <p>\&lt;value>false\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash; 访问代理类：client，mycluster，active配置失败自动切换实现方式&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>dfs.client.failover.proxy.provider.mycluster\&lt;/name></p> <p>\&lt;value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;/configuration></p> </blockquote> <ol> <li>拷贝配置好的hadoop环境到其他节点</li> </ol> <h3 id=835-hdfs-ha>8.3.5 启动HDFS-HA集群</h3> <ol> <li>在各个JournalNode节点上，输入以下命令启动journalnode服务</li> </ol> <blockquote> <p>sbin/hadoop-daemon.sh start journalnode</p> </blockquote> <ol> <li>在[nn1]上，对其进行格式化，并启动</li> </ol> <blockquote> <p>bin/hdfs namenode -format</p> <p>sbin/hadoop-daemon.sh start namenode</p> </blockquote> <ol> <li>在[nn2]上，同步nn1的元数据信息</li> </ol> <blockquote> <p>bin/hdfs namenode -bootstrapStandby</p> </blockquote> <ol> <li>启动[nn2]</li> </ol> <blockquote> <p>sbin/hadoop-daemon.sh start namenode</p> </blockquote> <ol> <li>查看web页面显示，如图3-21，3-22所示</li> </ol> <p><img alt src=f9f13ef08a4035ffec7e3c3bee3ffe9a.png></p> <blockquote> <p>图3-21 hadoop102(standby)</p> </blockquote> <p><img alt src=18eb0ceb4685be654a0b622f9821f0db.png></p> <blockquote> <p>图3-22 hadoop103(standby)</p> </blockquote> <ol> <li>在[nn1]上，启动所有datanode</li> </ol> <blockquote> <p>sbin/hadoop-daemons.sh start datanode</p> </blockquote> <ol> <li>将[nn1]切换为Active</li> </ol> <blockquote> <p>bin/hdfs haadmin -transitionToActive nn1</p> </blockquote> <ol> <li>查看是否Active</li> </ol> <blockquote> <p>bin/hdfs haadmin -getServiceState nn1</p> </blockquote> <h3 id=836-hdfs-ha>8.3.6 配置HDFS-HA自动故障转移</h3> <ol> <li>具体配置</li> </ol> <p>（1）在hdfs-site.xml中增加</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>dfs.ha.automatic-failover.enabled\&lt;/name></p> <p>\&lt;value>true\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <p>（2）在core-site.xml文件中增加</p> <blockquote> <p>\&lt;property></p> <p>\&lt;name>ha.zookeeper.quorum\&lt;/name></p> <p>\&lt;value>hadoop102:2181,hadoop103:2181,hadoop104:2181\&lt;/value></p> <p>\&lt;/property></p> </blockquote> <ol> <li>启动</li> </ol> <p>（1）关闭所有HDFS服务：</p> <blockquote> <p>sbin/stop-dfs.sh</p> </blockquote> <p>（2）启动Zookeeper集群：</p> <blockquote> <p>bin/zkServer.sh start</p> </blockquote> <p>（3）初始化HA在Zookeeper中状态：</p> <blockquote> <p>bin/hdfs zkfc -formatZK</p> </blockquote> <p>（4）启动HDFS服务：</p> <blockquote> <p>sbin/start-dfs.sh</p> </blockquote> <p>（5）在各个NameNode节点上启动DFSZK Failover Controller，先在哪台机器启动，哪个机器的NameNode就是Active NameNode</p> <blockquote> <p>sbin/hadoop-daemin.sh start zkfc</p> </blockquote> <ol> <li>验证</li> </ol> <p>（1）将Active NameNode进程kill</p> <blockquote> <p>kill -9 namenode的进程id</p> </blockquote> <p>（2）将Active NameNode机器断开网络</p> <blockquote> <p>service network stop</p> </blockquote> <h2 id=84-yarn-ha>8.4 YARN-HA配置</h2> <h3 id=841-yarn-ha>8.4.1 YARN-HA工作机制</h3> <ol> <li>官方文档：</li> </ol> <p><a href=http://hadoop.apache.org/docs/r2.7.2/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html>http://hadoop.apache.org/docs/r2.7.2/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html</a></p> <ol> <li>YARN-HA工作机制，如图3-23所示</li> </ol> <p><img alt src=fc12b6316da68ad30a7ccd7ed4c2e269.png></p> <p>图3-22 YARN-HA工作机制</p> <h3 id=842-yarn-ha>8.4.2 配置YARN-HA集群</h3> <ol> <li>环境准备</li> </ol> <blockquote> <p>（1）修改IP</p> <p>（2）修改主机名及主机名和IP地址的映射</p> <p>（3）关闭防火墙</p> <p>（4）ssh免密登录</p> <p>（5）安装JDK，配置环境变量等</p> </blockquote> <p>（6）配置Zookeeper集群</p> <ol> <li>规划集群</li> </ol> <p>表3-2</p> <table> <thead> <tr> <th>hadoop102</th> <th>hadoop103</th> <th>hadoop104</th> </tr> </thead> <tbody> <tr> <td>NameNode</td> <td>NameNode</td> <td></td> </tr> <tr> <td>JournalNode</td> <td>JournalNode</td> <td>JournalNode</td> </tr> <tr> <td>DataNode</td> <td>DataNode</td> <td>DataNode</td> </tr> <tr> <td>ZK</td> <td>ZK</td> <td>ZK</td> </tr> <tr> <td>ResourceManager</td> <td>ResourceManager</td> <td></td> </tr> <tr> <td>NodeManager</td> <td>NodeManager</td> <td>NodeManager</td> </tr> </tbody> </table> <ol> <li>具体配置</li> </ol> <p>（1）yarn-site.xml</p> <table> <thead> <tr> <th>\&lt;configuration></th> </tr> </thead> <tbody> <tr> <td></td> </tr> </tbody> </table> <blockquote> <p>\&lt;property></p> <p>\&lt;name>yarn.nodemanager.aux-services\&lt;/name></p> <p>\&lt;value>mapreduce_shuffle\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash;启用resourcemanager ha&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.ha.enabled\&lt;/name></p> <p>\&lt;value>true\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash;声明两台resourcemanager的地址&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.cluster-id\&lt;/name></p> <p>\&lt;value>cluster-yarn1\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.ha.rm-ids\&lt;/name></p> <p>\&lt;value>rm1,rm2\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.hostname.rm1\&lt;/name></p> <p>\&lt;value>hadoop102\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.hostname.rm2\&lt;/name></p> <p>\&lt;value>hadoop103\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash;指定zookeeper集群的地址&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.zk-address\&lt;/name></p> <p>\&lt;value>hadoop102:2181,hadoop103:2181,hadoop104:2181\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash;启用自动恢复&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.recovery.enabled\&lt;/name></p> <p>\&lt;value>true\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;!&ndash;指定resourcemanager的状态信息存储在zookeeper集群&ndash;></p> <p>\&lt;property></p> <p>\&lt;name>yarn.resourcemanager.store.class\&lt;/name> \&lt;value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore\&lt;/value></p> <p>\&lt;/property></p> <p>\&lt;/configuration></p> </blockquote> <p>（2）同步更新其他节点的配置信息</p> <ol> <li>启动HDFS</li> </ol> <blockquote> <p>（1）在各个JournalNode节点上，输入以下命令启动journalnode服务：</p> <p>sbin/hadoop-daemon.sh start journalnode</p> <p>（2）在[nn1]上，对其进行格式化，并启动：</p> <p>bin/hdfs namenode -format</p> <p>sbin/hadoop-daemon.sh start namenode</p> <p>（3）在[nn2]上，同步nn1的元数据信息：</p> <p>bin/hdfs namenode -bootstrapStandby</p> <p>（4）启动[nn2]：</p> <p>sbin/hadoop-daemon.sh start namenode</p> <p>（5）启动所有DataNode</p> <p>sbin/hadoop-daemons.sh start datanode</p> <p>（6）将[nn1]切换为Active</p> <p>bin/hdfs haadmin -transitionToActive nn1</p> </blockquote> <ol> <li>启动YARN</li> </ol> <p>（1）在hadoop102中执行：</p> <blockquote> <p>sbin/start-yarn.sh</p> </blockquote> <p>（2）在hadoop103中执行：</p> <blockquote> <p>sbin/yarn-daemon.sh start resourcemanager</p> </blockquote> <p>（3）查看服务状态，如图3-24所示</p> <blockquote> <p>bin/yarn rmadmin -getServiceState rm1</p> </blockquote> <p><img alt src=d1049d0f53d47166c42d7a8bc7b6b5d1.png></p> <p>图3-24 YARN的服务状态</p> <h2 id=85-hdfs-federation>8.5 HDFS Federation架构设计</h2> <ol> <li>NameNode架构的局限性</li> </ol> <blockquote> <p>（1）Namespace（命名空间）的限制</p> </blockquote> <p>由于NameNode在内存中存储所有的元数据（metadata），因此单个NameNode所能存储的对象（文件+块）数目受到NameNode所在JVM的heap size的限制。50G的heap能够存储20亿（200million）个对象，这20亿个对象支持4000个DataNode，12PB的存储（假设文件平均大小为40MB）。随着数据的飞速增长，存储的需求也随之增长。单个DataNode从4T增长到36T，集群的尺寸增长到8000个DataNode。存储的需求从12PB增长到大于100PB。</p> <p>（2）隔离问题</p> <p>由于HDFS仅有一个NameNode，无法隔离各个程序，因此HDFS上的一个实验程序就很有可能影响整个HDFS上运行的程序。</p> <p>（3）性能的瓶颈</p> <p>由于是单个NameNode的HDFS架构，因此整个HDFS文件系统的吞吐量受限于单个NameNode的吞吐量。</p> <ol> <li>HDFS Federation架构设计，如图3-25所示</li> </ol> <blockquote> <p>能不能有多个NameNode</p> <p>表3-3</p> </blockquote> <table> <thead> <tr> <th>NameNode</th> <th>NameNode</th> <th>NameNode</th> </tr> </thead> <tbody> <tr> <td>元数据</td> <td>元数据</td> <td>元数据</td> </tr> <tr> <td>Log</td> <td>machine</td> <td>电商数据/话单数据</td> </tr> </tbody> </table> <p>图3-25 HDFS Federation架构设计</p> <ol> <li>HDFS Federation应用思考</li> </ol> <blockquote> <p>不同应用可以使用不同NameNode进行数据管理</p> <p>图片业务、爬虫业务、日志审计业务</p> <p>Hadoop生态系统中，不同的框架使用不同的NameNode进行管理NameSpace。（隔离性）</p> </blockquote> </article> </div> </div> </main> <footer class=md-footer> <div class=md-footer-nav> <nav class="md-footer-nav__inner md-grid" aria-label=Footer> <a href=../Hadoop%E5%9F%BA%E7%A1%80/ title=入门 class="md-footer-nav__link md-footer-nav__link--prev" rel=prev> <div class="md-footer-nav__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg> </div> <div class=md-footer-nav__title> <div class=md-ellipsis> <span class=md-footer-nav__direction> 上一页 </span> 入门 </div> </div> </a> <a href=../Hadoop-MapReduce/ title=MapReduce class="md-footer-nav__link md-footer-nav__link--next" rel=next> <div class=md-footer-nav__title> <div class=md-ellipsis> <span class=md-footer-nav__direction> 下一页 </span> MapReduce </div> </div> <div class="md-footer-nav__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/></svg> </div> </a> </nav> </div> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-footer-copyright> <div class=md-footer-copyright__highlight> Copyright &copy; 2018 - 2029 Dayet 296577630@qq.com </div> Made with <a href=https://squidfunk.github.io/mkdocs-material/ target=_blank rel=noopener> Material for MkDocs </a> </div> </div> </div> </footer> </div> <script src=../../assets/javascripts/vendor.2d1db4bd.min.js></script> <script src=../../assets/javascripts/bundle.6627ddf3.min.js></script><script id=__lang type=application/json>{"clipboard.copy": "\u590d\u5236", "clipboard.copied": "\u5df2\u590d\u5236", "search.config.lang": "ja", "search.config.pipeline": "trimmer, stemmer", "search.config.separator": "[\\uff0c\\u3002]+", "search.result.placeholder": "\u952e\u5165\u4ee5\u5f00\u59cb\u641c\u7d22", "search.result.none": "\u6ca1\u6709\u627e\u5230\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.one": "\u627e\u5230 1 \u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c", "search.result.other": "# \u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u7ed3\u679c"}</script> <script>
        app = initialize({
          base: "../..",
          features: [],
          search: Object.assign({
            worker: "../../assets/javascripts/worker/search.5eca75d3.min.js"
          }, typeof search !== "undefined" && search)
        })
      </script> </body> </html>